/// <summary> /// Sets NameFormat /// </summary> /// <param name="options"></param> /// <param name="val"></param> /// <returns></returns> public static GroupingDataflowBlockOptions NameFormat(this GroupingDataflowBlockOptions options, string val) { if (options == null) { return(null); } options.NameFormat = val; return(options); }
protected DataFlowBatchDestination( IConnectionManager connectionManager = null, int batchSize = DefaultBatchSize, GroupingDataflowBlockOptions batchOptions = null, ExecutionDataflowBlockOptions executionOptions = null) : base(connectionManager) { BatchOptions = batchOptions ?? new(); ExecutionOptions = executionOptions ?? new(); BatchSize = batchSize; }
/// <summary> /// Sets MaxMessagesPerTask /// </summary> /// <param name="options"></param> /// <param name="val"></param> /// <returns></returns> public static GroupingDataflowBlockOptions MaxMessagesPerTask(this GroupingDataflowBlockOptions options, int val) { if (options == null) { return(null); } options.MaxMessagesPerTask = val; return(options); }
/// <summary> /// Sets TaskScheduler /// </summary> /// <param name="options"></param> /// <param name="val"></param> /// <returns></returns> public static GroupingDataflowBlockOptions TaskScheduler(this GroupingDataflowBlockOptions options, TaskScheduler val) { if (options == null) { return(null); } options.TaskScheduler = val; return(options); }
/// <summary> /// Sets CancellationToken /// </summary> /// <param name="options"></param> /// <param name="val"></param> /// <returns></returns> public static GroupingDataflowBlockOptions CancellationToken(this GroupingDataflowBlockOptions options, CancellationToken val) { if (options == null) { return(null); } options.CancellationToken = val; return(options); }
/// <summary> /// Sets MaxNumberOfGroups /// </summary> /// <param name="options"></param> /// <param name="val"></param> /// <returns></returns> public static GroupingDataflowBlockOptions MaxNumberOfGroups(this GroupingDataflowBlockOptions options, int val) { if (options == null) { return(null); } options.MaxNumberOfGroups = val; return(options); }
/// <summary> /// Sets Greedy /// </summary> /// <param name="options"></param> /// <param name="val"></param> /// <returns></returns> public static GroupingDataflowBlockOptions Greedy(this GroupingDataflowBlockOptions options, bool val = true) { if (options == null) { return(null); } options.Greedy = val; return(options); }
public void TestTriggerBatch_NonGreedyEmpty() { var dbo = new GroupingDataflowBlockOptions { Greedy = false }; var b = new BatchBlock <int>(3, dbo); Assert.Equal(expected: 0, actual: b.OutputCount); b.TriggerBatch(); Assert.Equal(expected: 0, actual: b.OutputCount); }
/// <summary> /// Create JoinBlock that take in T1, T2, and T3 /// </summary> /// <param name="options">Dataflow options for this block</param> /// <returns>JoinBlock which the inputs are wrapped around by IEnvelope</returns> internal JoinBlock <IEnvelope <T>, IEnvelope <T>, IEnvelope <T> > CreateJoinThreeBlock(GroupingDataflowBlockOptions options, CancellationTokenSource cancellationTokenSource) { if (options == null) { options = new GroupingDataflowBlockOptions(); } options.CancellationToken = cancellationTokenSource.Token; return(new JoinBlock <IEnvelope <T>, IEnvelope <T>, IEnvelope <T> >(options)); }
/// <summary> /// Sets BoundedCapacity /// </summary> /// <param name="options"></param> /// <param name="val"></param> /// <returns></returns> public static GroupingDataflowBlockOptions BoundedCapacity(this GroupingDataflowBlockOptions options, int val) { if (options == null) { return(null); } options.BoundedCapacity = val; return(options); }
/// <summary> /// Sets EnsureOrdered /// </summary> /// <param name="options"></param> /// <param name="val"></param> /// <returns></returns> public static GroupingDataflowBlockOptions EnsureOrdered(this GroupingDataflowBlockOptions options, bool val = true) { if (options == null) { return(null); } options.EnsureOrdered = val; return(options); }
public DbDestination( TableDefinition tableDefinition, IConnectionManager connectionManager = null, int batchSize = DefaultBatchSize, GroupingDataflowBlockOptions batchOptions = null, ExecutionDataflowBlockOptions executionOptions = null) : base(connectionManager, batchSize, batchOptions, executionOptions) { TableDefinition = tableDefinition ?? throw new ArgumentNullException(nameof(tableDefinition)); TypeInfo = new DbTypeInfo(typeof(TInput)); WriteBatchInTransaction = true; }
/// <summary>Initializes the shared resources.</summary> /// <param name="batchSize">The size of a batch to create.</param> /// <param name="dataflowBlockOptions">The options used to configure the shared resources. Assumed to be immutable.</param> /// <param name="batchSizeReachedAction">The action to invoke when a batch is completed.</param> /// <param name="allTargetsDecliningAction">The action to invoke when no more targets are accepting input.</param> /// <param name="exceptionAction">The action to invoke when an exception needs to be logged.</param> /// <param name="completionAction">The action to invoke when completing, typically invoked due to a call to Fault.</param> internal BatchedJoinBlockTargetSharedResources( int batchSize, GroupingDataflowBlockOptions dataflowBlockOptions, Action batchSizeReachedAction, Action allTargetsDecliningAction, Action <Exception> exceptionAction, Action completionAction) { Debug.Assert(batchSize >= 1, "A positive batch size is required."); Debug.Assert(batchSizeReachedAction != null, "Need an action to invoke for each batch."); Debug.Assert(allTargetsDecliningAction != null, "Need an action to invoke when all targets have declined."); _incomingLock = new object(); _batchSize = batchSize; // _remainingAliveTargets will be incremented when targets are added. // They must be added during construction of the BatchedJoin<...>. _remainingAliveTargets = 0; _remainingItemsInBatch = batchSize; // Configure what to do when batches are completed and/or all targets start declining _allTargetsDecliningPermanentlyAction = () => { // Invoke the caller's action allTargetsDecliningAction(); // Don't accept any more messages. We should already // be doing this anyway through each individual target's declining flag, // so setting it to true is just a precaution and is also helpful // when onceOnly is true. _decliningPermanently = true; }; _batchSizeReachedAction = () => { // Invoke the caller's action batchSizeReachedAction(); _batchesCreated++; // If this batched join is meant to be used for only a single // batch, invoke the completion logic. if (_batchesCreated >= dataflowBlockOptions.ActualMaxNumberOfGroups) { _allTargetsDecliningPermanentlyAction(); } // Otherwise, get ready for the next batch. else { _remainingItemsInBatch = _batchSize; } }; _exceptionAction = exceptionAction; _completionAction = completionAction; }
public static IEnumerable <IDataflowBlock> CreateBlocksWithNameFormat(string nameFormat) { var dataflowBlockOptions = new DataflowBlockOptions { NameFormat = nameFormat }; var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions { NameFormat = nameFormat }; var groupingDataflowBlockOptions = new GroupingDataflowBlockOptions { NameFormat = nameFormat }; return(CreateBlocksWithOptions(dataflowBlockOptions, executionDataflowBlockOptions, groupingDataflowBlockOptions)); }
/// <summary> /// Initializes a DataflowBatchOptions. /// </summary> /// <param name="batch"></param> /// <param name="link"></param> public DataflowBatchOptions(Action <GroupingDataflowBlockOptions> batch = null , Action <DataflowLinkOptions> link = null) { _batchOptions = DataflowDefaultOptions.DefaultGroupingBlockOptions; _linkOptions = DataflowDefaultOptions.DefaultLinkOptions; if (batch != null) { batch(_batchOptions); } if (link != null) { link(_linkOptions); } }
public static IEnumerable <IDataflowBlock> CreateBlocksWithCancellationToken(CancellationToken cancellationToken) { var dataflowBlockOptions = new DataflowBlockOptions { CancellationToken = cancellationToken }; var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions { CancellationToken = cancellationToken }; var groupingDataflowBlockOptions = new GroupingDataflowBlockOptions { CancellationToken = cancellationToken }; return(CreateBlocksWithOptions(dataflowBlockOptions, executionDataflowBlockOptions, groupingDataflowBlockOptions)); }
/// <summary> /// Initializes a DataflowWriteOnceOptions. /// </summary> /// <param name="writeOnce"></param> /// <param name="link"></param> public DataflowWriteOnceOptions(Action <GroupingDataflowBlockOptions> writeOnce = null , Action <DataflowLinkOptions> link = null) { _writeOnceOptions = DataflowDefaultOptions.DefaultGroupingBlockOptions; _linkOptions = DataflowDefaultOptions.DefaultLinkOptions; if (writeOnce != null) { writeOnce(_writeOnceOptions); } if (link != null) { link(_linkOptions); } }
static public void Run() { var opts = new GroupingDataflowBlockOptions { Greedy = false }; var jBlock = new JoinBlock <int, int>(opts); for (int i = 0; i < 10; i++) { Task <bool> task = jBlock.Target1.SendAsync(i); // needed to capture 'i' so we can use it in `ContinueWith` int iCopy = i; task.ContinueWith(t => { if (t.Result) { Console.WriteLine("Target1 accepted: " + iCopy); } else { Console.WriteLine("Target1 REFUSED: " + iCopy); } }); } for (int i = 0; i < 10; i++) { Task <bool> task = jBlock.Target2.SendAsync(i); // needed to capture 'i' so we can use it in `ContinueWith` int iCopy = i; task.ContinueWith(t => { if (t.Result) { Console.WriteLine("Target2 accepted: " + iCopy); } else { Console.WriteLine("Target2 REFUSED: " + iCopy); } }); } for (int i = 0; i < 10; i++) { Console.WriteLine(jBlock.Receive()); } Console.WriteLine("Done"); }
public TimeoutBatchBlock(int batchSize, int timeout, GroupingDataflowBlockOptions dataflowBlockOptions) { _batchBlock = new BatchBlock <T>(batchSize, dataflowBlockOptions); _timeoutTimer = new Timer(o => _batchBlock.TriggerBatch()); _timeoutBlock = new TransformBlock <T, T>(o => { _timeoutTimer.Change(timeout, Timeout.Infinite); return(o); }, new ExecutionDataflowBlockOptions { CancellationToken = dataflowBlockOptions.CancellationToken }); _link = _timeoutBlock.LinkTo(_batchBlock, new DataflowLinkOptions { PropagateCompletion = true }); }
/// <nodoc /> public VsoClient(IIpcLogger logger, DropDaemon dropDaemon) { Contract.Requires(dropDaemon?.DropConfig != null); m_logger = logger; m_dropDaemon = dropDaemon; m_config = dropDaemon.DropConfig; m_cancellationSource = new CancellationTokenSource(); logger.Info("Using drop config: " + JsonConvert.SerializeObject(m_config)); Stats = new DropStatistics(); // instantiate drop client m_dropClient = new ReloadingDropServiceClient( logger: logger, clientConstructor: CreateDropServiceClient); // create dataflow blocks var groupingOptions = new GroupingDataflowBlockOptions { Greedy = true }; var actionOptions = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = m_config.MaxParallelUploads }; var linkOptions = new DataflowLinkOptions { PropagateCompletion = true }; m_batchBlock = new BatchBlock <AddFileItem>(m_config.BatchSize, groupingOptions); m_bufferBlock = new BufferBlock <AddFileItem[]>(); // per http://blog.stephencleary.com/2012/11/async-producerconsumer-queue-using.html, good to have buffer when throttling m_actionBlock = new ActionBlock <AddFileItem[]>(ProcessAddFilesAsync, actionOptions); m_batchBlock.LinkTo(m_bufferBlock, linkOptions); m_bufferBlock.LinkTo(m_actionBlock, linkOptions); // create and set up timer for triggering the batch block TimeSpan timerInterval = m_config.NagleTime; m_batchTimer = new Timer(FlushBatchBlock, null, timerInterval, timerInterval); if (m_config.ArtifactLogName != null) { DropAppTraceSource.SingleInstance.SetSourceLevel(System.Diagnostics.SourceLevels.Verbose); Tracer.AddFileTraceListener(Path.Combine(m_config.LogDir, m_config.ArtifactLogName)); } }
public SynchronizedJoinBlock(Func <T1, T2, int> compareFunction, GroupingDataflowBlockOptions dataflowBlockOptions) { if (compareFunction == null) { throw new ArgumentNullException(nameof(compareFunction)); } if (dataflowBlockOptions == null) { throw new ArgumentNullException(nameof(dataflowBlockOptions)); } if (dataflowBlockOptions.BoundedCapacity > 0) { throw new NotSupportedException(); } if (!dataflowBlockOptions.Greedy) { throw new NotSupportedException(); } _compareFunction = compareFunction; _joinBlock = new JoinBlock <T1, T2>(dataflowBlockOptions); var sharedResourcesFieldInfo = typeof(JoinBlock <T1, T2>).GetField( "_sharedResources", BindingFlags.NonPublic | BindingFlags.Instance); var sharedResources = sharedResourcesFieldInfo.GetValue(_joinBlock); var joinFilledActionFieldInfo = sharedResources.GetType().GetField( "_joinFilledAction", BindingFlags.NonPublic | BindingFlags.Instance); Action action = () => { AddMessageToSourceRecursive( _target1Messages.Peek(), _target2Messages.Peek()); }; joinFilledActionFieldInfo.SetValue(sharedResources, action); _target1Messages = GetFieldValue <Queue <T1> >(Target1, "_messages"); _target2Messages = GetFieldValue <Queue <T2> >(Target2, "_messages"); var source = GetFieldValue <object>(_joinBlock, "_source"); var addMessageMethodInfo = source.GetType().GetMethod( "AddMessage", BindingFlags.NonPublic | BindingFlags.Instance); _addMessageToSource = (value) => { addMessageMethodInfo.Invoke(source, new[] { value }); }; }
/// <summary> /// Performs shallow clone of the options. /// </summary> public static GroupingDataflowBlockOptions Clone([NotNull] this GroupingDataflowBlockOptions source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } var result = new GroupingDataflowBlockOptions { BoundedCapacity = source.BoundedCapacity, CancellationToken = source.CancellationToken, MaxMessagesPerTask = source.MaxMessagesPerTask, NameFormat = source.NameFormat, TaskScheduler = source.TaskScheduler, Greedy = source.Greedy, MaxNumberOfGroups = source.MaxNumberOfGroups }; return(result); }
public void TestPropertyRoundtripping() { var dbo = new DataflowBlockOptions(); var edbo = new ExecutionDataflowBlockOptions(); var gdbo = new GroupingDataflowBlockOptions(); foreach (int value in new[] { 2, int.MaxValue, DataflowBlockOptions.Unbounded }) { SetAndTest(dbo, (o, v) => o.MaxMessagesPerTask = v, o => o.MaxMessagesPerTask, value); SetAndTest(dbo, (o, v) => o.BoundedCapacity = v, o => o.BoundedCapacity, value); SetAndTest(edbo, (o, v) => o.MaxDegreeOfParallelism = v, o => o.MaxDegreeOfParallelism, value); SetAndTest(gdbo, (o, v) => o.MaxNumberOfGroups = v, o => o.MaxNumberOfGroups, value); } SetAndTest(gdbo, (o, v) => o.MaxNumberOfGroups = v, o => o.MaxNumberOfGroups, long.MaxValue); foreach (TaskScheduler value in new[] { new ConcurrentExclusiveSchedulerPair().ConcurrentScheduler, TaskScheduler.Default }) { SetAndTest(dbo, (o, v) => o.TaskScheduler = v, o => o.TaskScheduler, value); } foreach (CancellationToken value in new[] { new CancellationToken(false), new CancellationToken(true), new CancellationTokenSource().Token }) { SetAndTest(dbo, (o, v) => o.CancellationToken = v, o => o.CancellationToken, value); } foreach (string value in new[] { "none", "foo {0}", "foo {0} bar {1}", "kaboom {0} {1} {2}" }) { SetAndTest(dbo, (o, v) => o.NameFormat = v, o => o.NameFormat, value); } foreach (bool value in DataflowTestHelpers.BooleanValues) { SetAndTest(dbo, (o, v) => o.EnsureOrdered = v, o => o.EnsureOrdered, value); } foreach (bool value in DataflowTestHelpers.BooleanValues) { SetAndTest(gdbo, (o, v) => o.Greedy = v, o => o.Greedy, value); } }
private void InitializeDataflow(CancellationToken cancellationToken = default) { var writeBlockSettings = new ExecutionDataflowBlockOptions() { CancellationToken = cancellationToken, BoundedCapacity = 2 }; var batchBlockSettings = new GroupingDataflowBlockOptions() { CancellationToken = cancellationToken, BoundedCapacity = _portion * 2 }; _writeBlock = new ActionBlock <T[]>(c => _storage.WriteEventLogDataAsync(c.ToList(), cancellationToken), writeBlockSettings); _batchBlock = new BatchBlock <T>(_portion, batchBlockSettings); _batchBlock.LinkTo(_writeBlock, new DataflowLinkOptions() { PropagateCompletion = true }); }
public async Task TestNonGreedyFailToConsumeReservedMessage() { var sources = Enumerable.Range(0, 2).Select(i => new DelegatePropagator <int, int> { ReserveMessageDelegate = delegate { return(true); }, ConsumeMessageDelegate = delegate(DataflowMessageHeader messageHeader, ITargetBlock <int> target, out bool messageConsumed) { messageConsumed = false; // fail consumption of a message already reserved Assert.Equal(expected: 0, actual: i); // shouldn't get to second source return(0); } }).ToArray(); var options = new GroupingDataflowBlockOptions { Greedy = false }; JoinBlock <int, int> join = new JoinBlock <int, int>(options); join.Target1.OfferMessage(new DataflowMessageHeader(1), 0, sources[0], consumeToAccept: true); // call back ConsumeMassage join.Target2.OfferMessage(new DataflowMessageHeader(1), 0, sources[1], consumeToAccept: true); // call back ConsumeMassage await Assert.ThrowsAsync <InvalidOperationException>(() => join.Completion); }
public void RunBoundingTests() { var options = new DataflowBlockOptions() { BoundedCapacity = ITargetBlockTestHelper.BOUNDED_CAPACITY }; var executionOptions = new ExecutionDataflowBlockOptions() { BoundedCapacity = ITargetBlockTestHelper.BOUNDED_CAPACITY }; var greedyOptions = new GroupingDataflowBlockOptions() { BoundedCapacity = ITargetBlockTestHelper.BOUNDED_CAPACITY, Greedy = true }; var nonGreedyOptions = new GroupingDataflowBlockOptions() { BoundedCapacity = ITargetBlockTestHelper.BOUNDED_CAPACITY, Greedy = false }; // "Normal" target blocks Assert.True(ITargetBlockTestHelper.TestBoundingTarget<int, int>(new ActionBlock<int>((Action<int>)ITargetBlockTestHelper.BoundingAction, executionOptions), greedy: true)); // BatchBlock Assert.True(ITargetBlockTestHelper.TestBoundingTarget<int, int[]>(new BatchBlock<int>(ITargetBlockTestHelper.BOUNDED_CAPACITY, greedyOptions), greedy: true)); Assert.True(ITargetBlockTestHelper.TestBoundingTarget<int, int[]>(new BatchBlock<int>(ITargetBlockTestHelper.BOUNDED_CAPACITY, nonGreedyOptions), greedy: false)); // JoinBlock Assert.True(ITargetBlockTestHelper.TestBoundingJoin2<int>(new JoinBlock<int, int>(greedyOptions), greedy: true)); Assert.True(ITargetBlockTestHelper.TestBoundingJoin3<int>(new JoinBlock<int, int, int>(nonGreedyOptions), greedy: false)); // JoinBlock.Target Assert.True(ITargetBlockTestHelper.TestBoundingGreedyJoinTarget2<int>(new JoinBlock<int, int>(greedyOptions), testedTargetIndex: 1)); Assert.True(ITargetBlockTestHelper.TestBoundingGreedyJoinTarget3<int>(new JoinBlock<int, int, int>(greedyOptions), testedTargetIndex: 2)); }
public AsyncEndpointExecutor(Endpoint endpoint, ICheckpointer checkpointer, EndpointExecutorConfig config, AsyncEndpointExecutorOptions options) { Preconditions.CheckNotNull(endpoint); Preconditions.CheckNotNull(config); this.checkpointer = Preconditions.CheckNotNull(checkpointer); this.cts = new CancellationTokenSource(); this.options = Preconditions.CheckNotNull(options); this.machine = new EndpointExecutorFsm(endpoint, checkpointer, config); this.closed = new AtomicBoolean(); // The three size variables below adjust the following parameters: // 1. MaxMessagesPerTask - the maximum number of messages the batch block will process before yielding // 2. BoundedCapacity - the size of the batch blocks input buffer // 3. BatchBlock ctor - the maximum size of each batch emitted by the block (can be smaller because of the timer) var batchOptions = new GroupingDataflowBlockOptions { MaxMessagesPerTask = MaxMessagesPerTask, BoundedCapacity = options.BatchSize }; var batchBlock = new BatchBlock <IMessage>(options.BatchSize, batchOptions); this.batchTimer = new Timer(Trigger, batchBlock, options.BatchTimeout, options.BatchTimeout); var processOptions = new ExecutionDataflowBlockOptions { BoundedCapacity = 1 }; var process = new ActionBlock <IMessage[]>(this.MessagesAction, processOptions); var linkOptions = new DataflowLinkOptions { PropagateCompletion = true }; batchBlock.LinkTo(process, linkOptions); this.head = batchBlock; this.tail = process; }
static public void Run() { var opts = new GroupingDataflowBlockOptions { Greedy = false }; var jBlock = new JoinBlock <int, int>(opts); for (int i = 0; i < 10; i++) { if (jBlock.Target1.Post(i)) { Console.WriteLine("Target1 accepted: " + i); } else { Console.WriteLine("Target1 REFUSED: " + i); } } for (int i = 0; i < 10; i++) { if (jBlock.Target2.Post(i)) { Console.WriteLine("Target2 accepted: " + i); } else { Console.WriteLine("Target2 REFUSED: " + i); } } for (int i = 0; i < 10; i++) { Console.WriteLine(jBlock.Receive()); } Console.WriteLine("Done"); }
private void InitializeDataflow(CancellationToken cancellationToken = default) { var writeBlockSettings = new ExecutionDataflowBlockOptions() { CancellationToken = cancellationToken, BoundedCapacity = _collectedFactor, MaxDegreeOfParallelism = _writingMaxDop }; var batchBlockSettings = new GroupingDataflowBlockOptions() { CancellationToken = cancellationToken, BoundedCapacity = _portion * _collectedFactor }; _writeBlock = new ActionBlock <EventLogItem[]>(c => _storage.WriteEventLogDataAsync(c.ToList(), cancellationToken), writeBlockSettings); _batchBlock = new BatchBlock <EventLogItem>(_portion, batchBlockSettings); _batchBlock.LinkTo(_writeBlock, new DataflowLinkOptions() { PropagateCompletion = true }); }
public void TestDefaultValues() { Action <DataflowBlockOptions> verifyBaseDefaults = dbo => { Assert.Equal(expected: TaskScheduler.Default, actual: dbo.TaskScheduler); Assert.Equal(expected: DataflowBlockOptions.Unbounded, actual: dbo.MaxMessagesPerTask); Assert.Equal(expected: DataflowBlockOptions.Unbounded, actual: dbo.BoundedCapacity); Assert.Equal(expected: CancellationToken.None, actual: dbo.CancellationToken); Assert.Equal(expected: -1, actual: DataflowBlockOptions.Unbounded); Assert.Equal(expected: @"{0} Id={1}", actual: dbo.NameFormat); }; verifyBaseDefaults(new DataflowBlockOptions()); var edbo = new ExecutionDataflowBlockOptions(); verifyBaseDefaults(edbo); Assert.Equal(expected: 1, actual: edbo.MaxDegreeOfParallelism); var gdbo = new GroupingDataflowBlockOptions(); verifyBaseDefaults(gdbo); Assert.Equal(expected: DataflowBlockOptions.Unbounded, actual: gdbo.MaxNumberOfGroups); Assert.Equal(expected: true, actual: gdbo.Greedy); }
public void TestDebuggerDisplaysAndTypeProxies() { // Test both canceled and non-canceled foreach (var ct in new[] { new CancellationToken(false), new CancellationToken(true) }) { // Some blocks have different code paths for whether they're greedy or not. // This helps with code-coverage. var dboBuffering = new DataflowBlockOptions(); var dboNoBuffering = new DataflowBlockOptions() { BoundedCapacity = 1 }; var dboExBuffering = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 2, CancellationToken = ct }; var dboExSpsc = new ExecutionDataflowBlockOptions { SingleProducerConstrained = true }; var dboExNoBuffering = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 2, BoundedCapacity = 1, CancellationToken = ct }; var dboGroupGreedy = new GroupingDataflowBlockOptions(); var dboGroupNonGreedy = new GroupingDataflowBlockOptions { Greedy = false }; // Item1 == test DebuggerDisplay, Item2 == test DebuggerTypeProxy, Item3 == object var objectsToTest = new Tuple <bool, bool, object>[] { // Primary Blocks // (Don't test DebuggerTypeProxy on instances that may internally have async operations in progress) Tuple.Create <bool, bool, object>(true, true, new ActionBlock <int>(i => {})), Tuple.Create <bool, bool, object>(true, true, new ActionBlock <int>(i => {}, dboExBuffering)), Tuple.Create <bool, bool, object>(true, true, new ActionBlock <int>(i => {}, dboExSpsc)), Tuple.Create <bool, bool, object>(true, false, SendAsyncMessages(new ActionBlock <int>(i => {}, dboExNoBuffering), 2)), Tuple.Create <bool, bool, object>(true, true, new TransformBlock <int, int>(i => i)), Tuple.Create <bool, bool, object>(true, true, new TransformBlock <int, int>(i => i, dboExBuffering)), Tuple.Create <bool, bool, object>(true, false, SendAsyncMessages(new TransformBlock <int, int>(i => i, dboExNoBuffering), 2)), Tuple.Create <bool, bool, object>(true, true, new TransformManyBlock <int, int>(i => new [] { i })), Tuple.Create <bool, bool, object>(true, true, new TransformManyBlock <int, int>(i => new [] { i }, dboExBuffering)), Tuple.Create <bool, bool, object>(true, false, SendAsyncMessages(new TransformManyBlock <int, int>(i => new [] { i }, dboExNoBuffering), 2)), Tuple.Create <bool, bool, object>(true, true, new BufferBlock <int>()), Tuple.Create <bool, bool, object>(true, true, new BufferBlock <int>(new DataflowBlockOptions() { NameFormat = "none" })), Tuple.Create <bool, bool, object>(true, true, new BufferBlock <int>(new DataflowBlockOptions() { NameFormat = "foo={0}, bar={1}" })), Tuple.Create <bool, bool, object>(true, true, new BufferBlock <int>(new DataflowBlockOptions() { NameFormat = "foo={0}, bar={1}, kaboom={2}" })), Tuple.Create <bool, bool, object>(true, true, new BufferBlock <int>(dboBuffering)), Tuple.Create <bool, bool, object>(true, false, SendAsyncMessages(new BufferBlock <int>(new DataflowBlockOptions { BoundedCapacity = 10 }), 20)), Tuple.Create <bool, bool, object>(true, true, new BroadcastBlock <int>(i => i)), Tuple.Create <bool, bool, object>(true, true, new BroadcastBlock <int>(i => i, dboBuffering)), Tuple.Create <bool, bool, object>(true, false, SendAsyncMessages(new BroadcastBlock <int>(i => i, dboNoBuffering), 20)), Tuple.Create <bool, bool, object>(true, true, new WriteOnceBlock <int>(i => i)), Tuple.Create <bool, bool, object>(true, false, SendAsyncMessages(new WriteOnceBlock <int>(i => i), 1)), Tuple.Create <bool, bool, object>(true, true, new WriteOnceBlock <int>(i => i, dboBuffering)), Tuple.Create <bool, bool, object>(true, true, new JoinBlock <int, int>()), Tuple.Create <bool, bool, object>(true, true, new JoinBlock <int, int>(dboGroupGreedy)), Tuple.Create <bool, bool, object>(true, true, new JoinBlock <int, int>(dboGroupNonGreedy)), Tuple.Create <bool, bool, object>(true, true, new JoinBlock <int, int, int>()), Tuple.Create <bool, bool, object>(true, true, new JoinBlock <int, int, int>(dboGroupGreedy)), Tuple.Create <bool, bool, object>(true, true, new JoinBlock <int, int, int>(dboGroupNonGreedy)), Tuple.Create <bool, bool, object>(true, true, new BatchedJoinBlock <int, int>(42)), Tuple.Create <bool, bool, object>(true, true, new BatchedJoinBlock <int, int>(42, dboGroupGreedy)), Tuple.Create <bool, bool, object>(true, true, new BatchedJoinBlock <int, int, int>(42, dboGroupGreedy)), Tuple.Create <bool, bool, object>(true, true, new BatchBlock <int>(42)), Tuple.Create <bool, bool, object>(true, true, new BatchBlock <int>(42, dboGroupGreedy)), Tuple.Create <bool, bool, object>(true, true, new BatchBlock <int>(42, dboGroupNonGreedy)), Tuple.Create <bool, bool, object>(true, true, DataflowBlock.Encapsulate <int, int>(new BufferBlock <int>(), new BufferBlock <int>())), Tuple.Create <bool, bool, object>(true, true, new BufferBlock <int>().AsObservable()), // Supporting and Internal Types Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new ActionBlock <int>(i => {}, dboExBuffering), "_defaultTarget")), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new ActionBlock <int>(i => {}, dboExNoBuffering), "_defaultTarget")), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(DebuggerAttributes.GetFieldValue(new ActionBlock <int>(i => {}), "_defaultTarget"), "_messages")), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new ActionBlock <int>(i => {}, dboExSpsc), "_spscTarget")), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(DebuggerAttributes.GetFieldValue(new ActionBlock <int>(i => {}, dboExSpsc), "_spscTarget"), "_messages")), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new BufferBlock <int>(), "_source")), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new BufferBlock <int>(new DataflowBlockOptions { BoundedCapacity = 10 }), "_source")), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new TransformBlock <int, int>(i => i, dboExBuffering), "_source")), Tuple.Create <bool, bool, object>(true, true, DebuggerAttributes.GetFieldValue(new TransformBlock <int, int>(i => i, dboExNoBuffering), "_reorderingBuffer")), Tuple.Create <bool, bool, object>(true, true, DebuggerAttributes.GetFieldValue(DebuggerAttributes.GetFieldValue(new TransformBlock <int, int>(i => i, dboExBuffering), "_source"), "_targetRegistry")), Tuple.Create <bool, bool, object>(true, true, DebuggerAttributes.GetFieldValue(DebuggerAttributes.GetFieldValue(WithLinkedTarget <TransformBlock <int, int>, int>(new TransformBlock <int, int>(i => i, dboExNoBuffering)), "_source"), "_targetRegistry")), Tuple.Create <bool, bool, object>(true, true, new JoinBlock <int, int>().Target1), Tuple.Create <bool, bool, object>(true, true, new JoinBlock <int, int>(dboGroupGreedy).Target1), Tuple.Create <bool, bool, object>(true, true, new JoinBlock <int, int>(dboGroupNonGreedy).Target1), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new JoinBlock <int, int>().Target1, "_sharedResources")), Tuple.Create <bool, bool, object>(true, true, new BatchedJoinBlock <int, int>(42).Target1), Tuple.Create <bool, bool, object>(true, true, new BatchedJoinBlock <int, int>(42, dboGroupGreedy).Target1), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new BatchBlock <int>(42), "_target")), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new BatchBlock <int>(42, dboGroupGreedy), "_target")), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new BatchBlock <int>(42, dboGroupNonGreedy), "_target")), Tuple.Create <bool, bool, object>(true, false, new BufferBlock <int>().LinkTo(new ActionBlock <int>(i => {}))), // ActionOnDispose Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new BroadcastBlock <int>(i => i), "_source")), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new BroadcastBlock <int>(i => i, dboGroupGreedy), "_source")), Tuple.Create <bool, bool, object>(true, false, DebuggerAttributes.GetFieldValue(new BroadcastBlock <int>(i => i, dboGroupNonGreedy), "_source")), Tuple.Create <bool, bool, object>(true, true, CreateNopLinkSource <int>()), Tuple.Create <bool, bool, object>(true, true, CreateFilteringSource <int>()), Tuple.Create <bool, bool, object>(true, true, CreateSendSource <int>()), Tuple.Create <bool, bool, object>(true, false, CreateReceiveTarget <int>()), Tuple.Create <bool, bool, object>(true, false, CreateOutputAvailableTarget()), Tuple.Create <bool, bool, object>(true, false, CreateChooseTarget <int>()), Tuple.Create <bool, bool, object>(true, false, new BufferBlock <int>().AsObservable().Subscribe(DataflowBlock.NullTarget <int>().AsObserver())), // Other Tuple.Create <bool, bool, object>(true, false, new DataflowMessageHeader(1)), }; // Test all DDAs and DTPAs foreach (var obj in objectsToTest) { if (obj.Item1) { DebuggerAttributes.ValidateDebuggerDisplayReferences(obj.Item3); } if (obj.Item2) { DebuggerAttributes.ValidateDebuggerTypeProxyProperties(obj.Item3); } } } }
public void TestTriggerBatch_NonGreedyEmpty() { var dbo = new GroupingDataflowBlockOptions { Greedy = false }; var b = new BatchBlock<int>(3, dbo); Assert.Equal(expected: 0, actual: b.OutputCount); b.TriggerBatch(); Assert.Equal(expected: 0, actual: b.OutputCount); }
public async Task TestTriggerBatch_NonGreedy() { var dbo = new GroupingDataflowBlockOptions { Greedy = false }; const int BatchSize = 10; for (int numPostponedMessages = 1; numPostponedMessages < BatchSize; numPostponedMessages++) { var b = new BatchBlock<int>(BatchSize, dbo); Assert.Equal(expected: 0, actual: b.OutputCount); for (int i = 0; i < numPostponedMessages; i++) { Assert.False(b.SendAsync(i).IsCompleted); } b.TriggerBatch(); int[] results = await b.ReceiveAsync(); Assert.Equal(expected: numPostponedMessages, actual: results.Length); for (int i = 0; i < results.Length; i++) { Assert.Equal(expected: i, actual: results[i]); } Assert.Equal(expected: 0, actual: b.OutputCount); b.TriggerBatch(); Assert.Equal(expected: 0, actual: b.OutputCount); } }