Esempio n. 1
0
        // This demonstrates the behavior of the WriteOnceBlock as it's easy to observe.
        //
        // Preface: I hate the name of this block. It's misleading. This should have been
        // called CloneBlock or CacheBlock. WriteOnceBlock sounds like you use the block once
        // and it then self-destructs.

        // How it works is simple, it will accept one published message and reject all other messages
        // coming to it. It will then take the first message and clone it and send it on every request
        // downstream.
        private static async Task WriteBlockBehaviorDemoAsync()
        {
            Console.WriteLine("WriteOneBlockDemo has started!");
            var block = new WriteOnceBlock <string>(input => input); // needs a clone function

            for (int i = 0; i < 5; i++)
            {
                if (block.Post(ProduceTimeData()))
                {
                    Console.WriteLine($"Message {i} was accepted");
                }
                else
                {
                    Console.WriteLine($"Message {i} was rejected");
                }
            }

            // Notice the count is much higher than input count and that I am not
            // waiting on it to signal no more data is coming, as it always has data.
            for (int i = 0; i < 15; i++)
            {
                var output = await block.ReceiveAsync().ConfigureAwait(false);

                Console.WriteLine($"ReceivedMessage {i}: {output}");
            }

            block.Complete();
            await block.Completion.ConfigureAwait(false);

            Console.WriteLine("Finished!");
            Console.ReadKey();
        }
        public IEnumerable <string> WriteOnceBlockUsage(int numberOfIteration, int minValue)
        {
            Console.WriteLine($"Inside {nameof(TplDataflow2BufferingBlocksController)} - {nameof(WriteOnceBlockUsage)}");

            var strings = new BlockingCollection <string>();

            // Create the members of the pipeline.
            var WriteOnceBlockGivenInputToASubscriber = new WriteOnceBlock <string>(null);
            var actionBlockSubscriber = new ActionBlock <string>(stringInput =>
                                                                 Functions.AddInputIntoTheGivenList(strings, stringInput, "Subscriber")
                                                                 );

            // Connect the dataflow blocks to form a pipeline.
            WriteOnceBlockGivenInputToASubscriber.LinkTo(actionBlockSubscriber, DataflowOptions.LinkOptions);

            // Start WriteOnceBlockUsage pipeline with the input values.
            for (var i = minValue; i <= minValue + numberOfIteration; i++)
            {
                WriteOnceBlockGivenInputToASubscriber.Post($"Value = {i}");
            }

            // Mark the head of the pipeline as complete.
            WriteOnceBlockGivenInputToASubscriber.Complete();

            // Wait for the last block in the pipeline to process all messages.
            actionBlockSubscriber.Completion.Wait();

            return(strings);
        }
        public async Task WriteOnceWithAction()
        {
            var block = new WriteOnceBlock <int>(a => a);
            var print = new ActionBlock <int>(a => Console.WriteLine($"Message: {a}"));

            block.LinkTo(print);

            for (int i = 0; i < 10; i++)
            {
                if (block.Post(i))
                {
                    Console.WriteLine($"Acceped {i}");
                }
                else
                {
                    Console.WriteLine($"Rejected {i}");
                }
            }

            block.Complete();
            await block.Completion;

            print.Complete();
            await print.Completion;

            Console.WriteLine("Done!");
        }
Esempio n. 4
0
        private static void TestSync4()
        {
            wb.LinkTo(displayBlock);
            wb.LinkTo(saveBlock);
            wb.LinkTo(sendBlock);

            for (int i = 0; i < 4; i++)
            {
                wb.Post(i);
            }

            wb.Complete();
            Console.WriteLine("Post Finished");
            wb.Completion.Wait();
            Console.WriteLine("Process Finished");
            Console.WriteLine("Recive:" + wb.Receive());
        }
Esempio n. 5
0
        // Demo of it being used with other blocks.
        //
        // Only one push message propagates to the ActionBlock so only one message is received.
        private static async Task SimpleDemoAsync()
        {
            Console.WriteLine("WriteOneBlockDemo has started!");
            var options = new DataflowLinkOptions {
                PropagateCompletion = true
            };
            var writeBlock  = new WriteOnceBlock <string>(input => input);
            var actionBlock = new ActionBlock <string>(Console.WriteLine);

            writeBlock.LinkTo(actionBlock, options);

            for (int i = 0; i < 5; i++)
            {
                await writeBlock.SendAsync(ProduceTimeData()).ConfigureAwait(false);
            }

            writeBlock.Complete();
            await actionBlock.Completion.ConfigureAwait(false);

            Console.WriteLine("Finished!");
            Console.ReadKey();
        }
Esempio n. 6
0
        public void TestStatusAfterComplete()
        {
            bool passed = true;

            var writeOnce = new WriteOnceBlock <int>(x => x);

            writeOnce.Complete();
            try
            {
                writeOnce.Completion.Wait();
                Console.WriteLine("Completed without exception - Passed");
                passed = writeOnce.Completion.Status == TaskStatus.RanToCompletion;
                Console.WriteLine("Status ({0}) - {1}", writeOnce.Completion.Status, passed ? "Passed" : "FAILED");
            }
            catch (AggregateException ae)
            {
                ae.Handle(e => e is TaskCanceledException);
                passed = false;
                Console.WriteLine("Completed without exception - FAILED");
            }

            Assert.True(passed, "Test failed.");
        }
Esempio n. 7
0
        public IDisposable LinkTo(ITargetBlock <IEnumerable <T> > target, DataflowLinkOptions linkOptions)
        {
            var emitter = new WriteOnceBlock <IEnumerable <T> >(items => items);

            // When the AccumBlock completes, send all the items to the emitter and complete it.
            AccumBlock.Completion.ContinueWith(async o =>
            {
                if (o.IsFaulted)
                {
                    ((ITargetBlock <IEnumerable <T> >)emitter).Fault(o.Exception);
                }
                else
                {
                    await emitter.SendAsync(Accumulator);
                    emitter.Complete();
                    Logger.LogTrace("emitter complete.");
                }
            });
            Completion = emitter.Completion;
            var disposable = emitter.LinkTo(target, linkOptions);

            return(disposable);
        }
        public async Task TestOutputAvailableAsync_DataAfterCompletion()
        {
            foreach (bool withUncanceledToken in DataflowTestHelpers.BooleanValues)
                foreach (bool withData in DataflowTestHelpers.BooleanValues)
                {
                    var wob = new WriteOnceBlock<int>(_ => _);
                    if (withData)
                        wob.Post(42);
                    else
                        wob.Complete();
                    await wob.Completion;

                    Task<bool> t = withUncanceledToken ?
                        wob.OutputAvailableAsync(new CancellationTokenSource().Token) :
                        wob.OutputAvailableAsync();

                    Assert.Equal(expected: withData, actual: await t);
                }
        }
Esempio n. 9
0
        public void RunWriteOnceBlockConformanceTests()
        {
            bool passed = true, localPassed = true;

            {
                // Test posting then receiving
                localPassed = true;
                var wob             = new WriteOnceBlock <int>(i => i);
                int successfulPosts = 0;
                for (int i = 10; i <= 20; i++)
                {
                    successfulPosts += wob.Post(i) ? 1 : 0;
                }
                localPassed |= successfulPosts == 1;
                localPassed |= wob.Receive() == 10;
                Console.WriteLine("{0}: Posting then receiving", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test receiving then posting
                localPassed = true;
                var wob = new WriteOnceBlock <int>(i => i);
                Task.Factory.StartNew(() =>
                {
                    Task.Delay(1000).Wait();
                    wob.Post(42);
                });
                localPassed |= wob.Receive() == 42;
                localPassed |= wob.Post(43) == false;
                wob.Completion.Wait();
                Console.WriteLine("{0}: Receiving then posting", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test broadcasting
                localPassed = true;
                var wob = new WriteOnceBlock <int>(i => i + 1);
                var tb1 = new TransformBlock <int, int>(i => i);
                var tb2 = new TransformBlock <int, int>(i => i);
                var tb3 = new TransformBlock <int, int>(i => i);
                wob.LinkTo(tb1);
                wob.LinkTo(tb2);
                wob.LinkTo(tb3);
                wob.Post(42);
                localPassed |= tb1.Receive() == 43;
                localPassed |= tb2.Receive() == 43;
                localPassed |= tb3.Receive() == 43;
                Console.WriteLine("{0}: Broadcasting", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test using a precanceled token
                localPassed = true;
                try
                {
                    var cts = new CancellationTokenSource();
                    cts.Cancel();
                    var dbo = new DataflowBlockOptions {
                        CancellationToken = cts.Token
                    };
                    var wob = new WriteOnceBlock <int>(i => i, dbo);

                    int         ignoredValue;
                    IList <int> ignoredValues;
                    localPassed &= wob.LinkTo(new ActionBlock <int>(delegate { })) != null;
                    localPassed &= wob.SendAsync(42).Result == false;
                    localPassed &= ((IReceivableSourceBlock <int>)wob).TryReceiveAll(out ignoredValues) == false;
                    localPassed &= wob.Post(42) == false;
                    localPassed &= wob.TryReceive(out ignoredValue) == false;
                    localPassed &= wob.Completion != null;
                    wob.Complete();
                }
                catch (Exception)
                {
                    localPassed = false;
                }
                Console.WriteLine("{0}: Precanceled tokens work correctly", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test using token canceled after construction
                localPassed = true;
                try
                {
                    var cts = new CancellationTokenSource();
                    var dbo = new DataflowBlockOptions {
                        CancellationToken = cts.Token
                    };
                    var wob = new WriteOnceBlock <int>(i => i, dbo);
                    cts.Cancel();

                    int         ignoredValue;
                    IList <int> ignoredValues;
                    localPassed &= wob.LinkTo(new ActionBlock <int>(delegate { })) != null;
                    localPassed &= wob.SendAsync(42).Result == false;
                    localPassed &= ((IReceivableSourceBlock <int>)wob).TryReceiveAll(out ignoredValues) == false;
                    localPassed &= wob.Post(42) == false;
                    localPassed &= wob.TryReceive(out ignoredValue) == false;
                    localPassed &= wob.Completion != null;
                    wob.Complete();
                }
                catch (Exception)
                {
                    localPassed = false;
                }
                Console.WriteLine("{0}: Precanceled tokens work correctly", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            Assert.True(passed, "Test failed.");
        }
        public void RunWriteOnceBlockConformanceTests()
        {
            bool passed = true, localPassed = true;
            {
                // Test posting then receiving
                localPassed = true;
                var wob = new WriteOnceBlock<int>(i => i);
                int successfulPosts = 0;
                for (int i = 10; i <= 20; i++)
                {
                    successfulPosts += wob.Post(i) ? 1 : 0;
                }
                localPassed |= successfulPosts == 1;
                localPassed |= wob.Receive() == 10;
                Console.WriteLine("{0}: Posting then receiving", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test receiving then posting
                localPassed = true;
                var wob = new WriteOnceBlock<int>(i => i);
                Task.Factory.StartNew(() =>
                {
                    Task.Delay(1000).Wait();
                    wob.Post(42);
                });
                localPassed |= wob.Receive() == 42;
                localPassed |= wob.Post(43) == false;
                wob.Completion.Wait();
                Console.WriteLine("{0}: Receiving then posting", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test broadcasting
                localPassed = true;
                var wob = new WriteOnceBlock<int>(i => i + 1);
                var tb1 = new TransformBlock<int, int>(i => i);
                var tb2 = new TransformBlock<int, int>(i => i);
                var tb3 = new TransformBlock<int, int>(i => i);
                wob.LinkTo(tb1);
                wob.LinkTo(tb2);
                wob.LinkTo(tb3);
                wob.Post(42);
                localPassed |= tb1.Receive() == 43;
                localPassed |= tb2.Receive() == 43;
                localPassed |= tb3.Receive() == 43;
                Console.WriteLine("{0}: Broadcasting", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test using a precanceled token
                localPassed = true;
                try
                {
                    var cts = new CancellationTokenSource();
                    cts.Cancel();
                    var dbo = new DataflowBlockOptions { CancellationToken = cts.Token };
                    var wob = new WriteOnceBlock<int>(i => i, dbo);

                    int ignoredValue;
                    IList<int> ignoredValues;
                    localPassed &= wob.LinkTo(new ActionBlock<int>(delegate { })) != null;
                    localPassed &= wob.SendAsync(42).Result == false;
                    localPassed &= ((IReceivableSourceBlock<int>)wob).TryReceiveAll(out ignoredValues) == false;
                    localPassed &= wob.Post(42) == false;
                    localPassed &= wob.TryReceive(out ignoredValue) == false;
                    localPassed &= wob.Completion != null;
                    wob.Complete();
                }
                catch (Exception)
                {
                    localPassed = false;
                }
                Console.WriteLine("{0}: Precanceled tokens work correctly", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test using token canceled after construction
                localPassed = true;
                try
                {
                    var cts = new CancellationTokenSource();
                    var dbo = new DataflowBlockOptions { CancellationToken = cts.Token };
                    var wob = new WriteOnceBlock<int>(i => i, dbo);
                    cts.Cancel();

                    int ignoredValue;
                    IList<int> ignoredValues;
                    localPassed &= wob.LinkTo(new ActionBlock<int>(delegate { })) != null;
                    localPassed &= wob.SendAsync(42).Result == false;
                    localPassed &= ((IReceivableSourceBlock<int>)wob).TryReceiveAll(out ignoredValues) == false;
                    localPassed &= wob.Post(42) == false;
                    localPassed &= wob.TryReceive(out ignoredValue) == false;
                    localPassed &= wob.Completion != null;
                    wob.Complete();
                }
                catch (Exception)
                {
                    localPassed = false;
                }
                Console.WriteLine("{0}: Precanceled tokens work correctly", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            Assert.True(passed, "Test failed.");
        }
        public void TestStatusAfterComplete()
        {
            bool passed = true;

            var writeOnce = new WriteOnceBlock<int>(x => x);
            writeOnce.Complete();
            try
            {
                writeOnce.Completion.Wait();
                Console.WriteLine("Completed without exception - Passed");
                passed = writeOnce.Completion.Status == TaskStatus.RanToCompletion;
                Console.WriteLine("Status ({0}) - {1}", writeOnce.Completion.Status, passed ? "Passed" : "FAILED");
            }
            catch (AggregateException ae)
            {
                ae.Handle(e => e is TaskCanceledException);
                passed = false;
                Console.WriteLine("Completed without exception - FAILED");
            }

            Assert.True(passed, "Test failed.");
        }
        static void Main(string[] args)
        {
            var batchRequests = new BatchBlock <int>(batchSize: 10);


            BroadcastBlock <int> br      = new BroadcastBlock <int>(x => x);
            ActionBlock <int>    actionx = new ActionBlock <int>((i) => Console.WriteLine(i));

            br.LinkTo(actionx, x => x > 10);



            MyProcessBlock pb = new MyProcessBlock();

            pb.LinkTo(actionx);



            var sendToDb = new ActionBlock <int[]>(reqs => Console.WriteLine(reqs.Length));

            batchRequests.LinkTo(sendToDb);


            for (int i = 0; i < 100; i++)
            {
                batchRequests.Post(i);
            }



            WriteOnceBlock <int> wo     = new WriteOnceBlock <int>(x => x);
            ActionBlock <int>    action = new ActionBlock <int>((i) => Console.WriteLine(i));

            wo.LinkTo(action, new DataflowLinkOptions {
                PropagateCompletion = true
            });

            wo.Post(1);
            wo.Post(2);
            wo.Post(3);
            wo.Post(4);
            wo.Post(5);
            wo.Complete();



            BroadcastBlock <int> b = new BroadcastBlock <int>(x => x);



            TransformBlock <int, int> t2 = new TransformBlock <int, int>(x => x);
            TransformBlock <int, int> t  = new TransformBlock <int, int>(x => x);

            JoinBlock <int, int> join = new JoinBlock <int, int>();

            ActionBlock <Tuple <int, int> > action2 = new ActionBlock <Tuple <int, int> >((i) => Console.WriteLine("{0}-{1}", i.Item1, i.Item2), new ExecutionDataflowBlockOptions {
                BoundedCapacity = 10, MaxMessagesPerTask = 30
            });

            b.LinkTo(t, x => x > 10);
            b.LinkTo(t2);

            t.LinkTo(action, x => x > 10);
            t2.LinkTo(action, x => x > 10);
            t.LinkTo(join.Target1);
            t2.LinkTo(join.Target1);
            join.LinkTo(action2);

            DataFlowDebuggerSide.TestShowVisualizer(b);
        }
Esempio n. 13
0
        /// <summary>
        /// Connect to a target on first of bound proxies, or use ping based dynamic lookup
        /// </summary>
        /// <param name="address"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        public override async Task ConnectAsync(SocketAddress address, CancellationToken ct)
        {
            Info.Address = address;
            if (Info.Address.Family == AddressFamily.Bound)
            {
                // Unwrap proxy and connect address.  If not bound, use local address to bind to.
                if (_boundEndpoint == null)
                {
                    _boundEndpoint = address;
                    // Unwrap bound address
                    while (_boundEndpoint.Family == AddressFamily.Bound)
                    {
                        _boundEndpoint = ((BoundSocketAddress)_boundEndpoint).LocalAddress;
                    }
                }
                Info.Address = ((BoundSocketAddress)Info.Address).RemoteAddress;
            }

            //
            // Get the named host from the registry if it exists - there should only be one...
            // This is the host we shall connect to.  It can contain proxies to use as well.
            //
            var hostList = await Provider.NameService.LookupAsync(
                Info.Address.ToString(), NameRecordType.Host, ct).ConfigureAwait(false);

            Host = hostList.FirstOrDefault();
            if (Host == null)
            {
                // If there is no host in the registry, create a fake host record for this address
                Host = new NameRecord(NameRecordType.Host, Info.Address.ToString());
            }
            else
            {
                if (!Host.Name.Equals(Info.Address.ToString(), StringComparison.CurrentCultureIgnoreCase))
                {
                    // Translate the address to host address
                    Info.Address = new ProxySocketAddress(Host.Name);
                }
            }

            // Commit all options that were set until now into info
            Info.Options.UnionWith(_optionCache.Select(p => Property <ulong> .Create(
                                                           (uint)p.Key, p.Value)));

            //
            // Create tpl network for connect - prioritize input above errored attempts using
            // prioritized scheduling queue.
            //
            var retries = new CancellationTokenSource();

            ct.Register(() => retries.Cancel());
            var errors = new TransformBlock <DataflowMessage <INameRecord>, DataflowMessage <INameRecord> >(
                async(error) => {
                if (error.FaultCount > 0)
                {
                    Host.RemoveReference(error.Arg.Address);
                    await Provider.NameService.AddOrUpdateAsync(Host, retries.Token).ConfigureAwait(false);
                    ProxyEventSource.Log.LinkFailure(this, error.Arg, Host, error.LastFault);
                }
                await Task.Delay((error.FaultCount + 1) * _throttleDelayMs, retries.Token).ConfigureAwait(false);
                return(error);
            },
                new ExecutionDataflowBlockOptions {
                NameFormat             = "Error (Connect) Id={1}",
                MaxDegreeOfParallelism = 2, // 2 parallel retries
                CancellationToken      = retries.Token
            });

            var linkAdapter = DataflowMessage <INameRecord> .CreateAdapter(
                new ExecutionDataflowBlockOptions {
                NameFormat                = "Adapt (Connect) Id={1}",
                CancellationToken         = ct,
                MaxDegreeOfParallelism    = DataflowBlockOptions.Unbounded,
                MaxMessagesPerTask        = DataflowBlockOptions.Unbounded,
                SingleProducerConstrained = true,
                EnsureOrdered             = false
            });

            var linkQuery = Provider.NameService.Read(
                new ExecutionDataflowBlockOptions {
                NameFormat        = "Query (Connect) Id={1}",
                CancellationToken = ct,
                EnsureOrdered     = true
            });

            var pinger = CreatePingBlock(errors, Info.Address,
                                         new ExecutionDataflowBlockOptions {
                NameFormat             = "Ping (Connect) Id={1}",
                CancellationToken      = ct,
                MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
                MaxMessagesPerTask     = 1,
                EnsureOrdered          = false
            });

            var linker = CreateLinkBlock(errors,
                                         new ExecutionDataflowBlockOptions {
                NameFormat             = "Link (Connect) Id={1}",
                CancellationToken      = ct,
                MaxDegreeOfParallelism = 1, // Ensure one link is created at a time.
                MaxMessagesPerTask     = DataflowBlockOptions.Unbounded,
                EnsureOrdered          = false
            });

            var connection = new WriteOnceBlock <IProxyLink>(l => l,
                                                             new DataflowBlockOptions {
                NameFormat         = "Final (Connect) Id={1}",
                MaxMessagesPerTask = 1, // Auto complete when link is created
                EnsureOrdered      = false
            });

            linkQuery.ConnectTo(linkAdapter);
            linkAdapter.ConnectTo(linker);
            errors.ConnectTo(pinger);
            pinger.ConnectTo(linker);
            linker.ConnectTo(connection);

            //
            // Now connect by starting the connection pipeline from query source...
            //
            if (_boundEndpoint != null)
            {
                //
                // User asked for specific set of proxies. Try linking with each
                // until we have a successful link.
                //
                await linkQuery.SendAsync(r => r.Matches(_boundEndpoint,
                                                         NameRecordType.Proxy), ct).ConfigureAwait(false);
            }
            else
            {
                //
                // Consider all endpoints - if the host has a candidate list
                // use this list to directly link, and then ping remaining with
                // a throttle.  Otherwise do a full ping.
                //
                var pingAdapter = DataflowMessage <INameRecord> .CreateAdapter(
                    new ExecutionDataflowBlockOptions {
                    NameFormat                = "Any (Connect) Id={1}",
                    CancellationToken         = ct,
                    MaxDegreeOfParallelism    = DataflowBlockOptions.Unbounded,
                    MaxMessagesPerTask        = DataflowBlockOptions.Unbounded,
                    SingleProducerConstrained = true,
                    EnsureOrdered             = false
                });

                var remaining = Provider.NameService.Read(
                    new ExecutionDataflowBlockOptions {
                    NameFormat        = "Remaining (Connect) Id={1}",
                    CancellationToken = ct,
                    EnsureOrdered     = true
                });

                remaining.ConnectTo(pingAdapter);

                if (Host.References.Any())
                {
                    // Delay ping through errors path to give references time to link...
                    pingAdapter.ConnectTo(errors);
                    await linkQuery.SendAsync(r => r.Matches(Host.References,
                                                             NameRecordType.Proxy), ct).ConfigureAwait(false);
                }
                else
                {
                    // Send directly to ping
                    pingAdapter.ConnectTo(pinger);
                }

                await remaining.SendAsync(r => r.IsProxyForHost(Info.Address), ct)
                .ConfigureAwait(false);
            }

            // Wait until a connected link is received.  Then cancel the remainder of the pipeline.
            try {
                _link = await connection.ReceiveAsync(ct);

                connection.Complete();
                retries.Cancel();

                Host.AddReference(_link.Proxy.Address);
                Host.LastActivity = _link.Proxy.LastActivity = DateTime.Now;
                await Provider.NameService.AddOrUpdateAsync(_link.Proxy, ct).ConfigureAwait(false);
            }
            catch (Exception e) {
                throw SocketException.Create("Failed to connect", e);
            }
            finally {
                await Provider.NameService.AddOrUpdateAsync(Host, ct).ConfigureAwait(false);
            }
        }