private void ProcessDispatches( ArrayDeque<NamedWindowConsumerLatch> dispatches, IDictionary<EPStatementAgentInstanceHandle, object> dispatchesPerStmt) { try { foreach (var latch in dispatches) { foreach (var entry in latch.DispatchTo) { var handle = entry.Key; var perStmtObj = dispatchesPerStmt.Get(handle); if (perStmtObj == null) { dispatchesPerStmt.Put(handle, latch); } else if (perStmtObj is IList<NamedWindowConsumerLatch> windowConsumerLatches) { windowConsumerLatches.Add(latch); } else { // convert from object to list var unitObj = (NamedWindowConsumerLatch) perStmtObj; IList<NamedWindowConsumerLatch> list = new List<NamedWindowConsumerLatch>(); list.Add(unitObj); list.Add(latch); dispatchesPerStmt.Put(handle, list); } } } // Dispatch - with or without metrics reporting if (metricReportingService.IsMetricsReportingEnabled) { foreach (var entry in dispatchesPerStmt) { var handle = entry.Key; var perStmtObj = entry.Value; // dispatch of a single result to the statement if (perStmtObj is NamedWindowConsumerLatch) { var unit = (NamedWindowConsumerLatch) perStmtObj; var newData = unit.DeltaData.NewData; var oldData = unit.DeltaData.OldData; if (handle.StatementHandle.MetricsHandle.IsEnabled) { var performanceMetric = PerformanceMetricsHelper.Call( () => ProcessHandle(handle, unit.DispatchTo.Get(handle), newData, oldData)); metricReportingService.AccountTime( handle.StatementHandle.MetricsHandle, performanceMetric, performanceMetric.NumInput); } else { var entries = unit.DispatchTo; var items = entries.Get(handle); if (items != null) { ProcessHandle(handle, items, newData, oldData); } } if (isPrioritized && handle.IsPreemptive) { break; } continue; } // dispatch of multiple results to a the same statement, need to aggregate per consumer view var deltaPerConsumer = GetDeltaPerConsumer(perStmtObj, handle); if (handle.StatementHandle.MetricsHandle.IsEnabled) { var performanceMetric = PerformanceMetricsHelper.Call( () => ProcessHandleMultiple(handle, deltaPerConsumer)); metricReportingService.AccountTime( handle.StatementHandle.MetricsHandle, performanceMetric, performanceMetric.NumInput); } else { ProcessHandleMultiple(handle, deltaPerConsumer); } if (isPrioritized && handle.IsPreemptive) { break; } } } else { foreach (var entry in dispatchesPerStmt) { var handle = entry.Key; var perStmtObj = entry.Value; // dispatch of a single result to the statement if (perStmtObj is NamedWindowConsumerLatch) { var unit = (NamedWindowConsumerLatch) perStmtObj; var newData = unit.DeltaData.NewData; var oldData = unit.DeltaData.OldData; ProcessHandle(handle, unit.DispatchTo.Get(handle), newData, oldData); if (isPrioritized && handle.IsPreemptive) { break; } continue; } // dispatch of multiple results to a the same statement, need to aggregate per consumer view var deltaPerConsumer = GetDeltaPerConsumer(perStmtObj, handle); ProcessHandleMultiple(handle, deltaPerConsumer); if (isPrioritized && handle.IsPreemptive) { break; } } } } finally { foreach (var latch in dispatches) { latch.Done(); } dispatchesPerStmt.Clear(); dispatches.Clear(); } }
private void ProcessDispatches( ArrayDeque<NamedWindowConsumerLatch> dispatches, ArrayDeque<NamedWindowConsumerLatch> work, IDictionary<EPStatementAgentInstanceHandle, object> dispatchesPerStmt) { if (dispatches.Count == 1) { var latch = dispatches.First; try { latch.Await(); var newData = latch.DeltaData.NewData; var oldData = latch.DeltaData.OldData; if (metricReportingService.IsMetricsReportingEnabled) { foreach (var entry in latch.DispatchTo) { var handle = entry.Key; if (handle.StatementHandle.MetricsHandle.IsEnabled) { var performanceMetric = PerformanceMetricsHelper.Call( () => ProcessHandle(handle, entry.Value, newData, oldData), 1); metricReportingService.AccountTime( handle.StatementHandle.MetricsHandle, performanceMetric, performanceMetric.NumInput); } else { ProcessHandle(handle, entry.Value, newData, oldData); } if (isPrioritized && handle.IsPreemptive) { break; } } } else { foreach (var entry in latch.DispatchTo) { var handle = entry.Key; ProcessHandle(handle, entry.Value, newData, oldData); if (isPrioritized && handle.IsPreemptive) { break; } } } } finally { latch.Done(); } return; } // Multiple different-result dispatches to same or different statements are needed in two situations: // a) an event comes in, triggers two insert-into statements inserting into the same named window and the window produces 2 results // b) a time batch is grouped in the named window, and a timer fires for both groups at the same time producing more then one result // c) two on-merge/update/delete statements fire for the same arriving event each updating the named window // Most likely all dispatches go to different statements since most statements are not joins of // named windows that produce results at the same time. Therefore sort by statement handle. // We need to process in N-element chains to preserve dispatches that are next to each other for the same thread. while (!dispatches.IsEmpty()) { // the first latch always gets awaited var first = dispatches.RemoveFirst(); first.Await(); work.Add(first); // determine which further latches are in this chain and add these, skipping await for any latches in the chain dispatches.RemoveWhere( (next, continuation) => { var result = next.Earlier == null || work.Contains(next.Earlier); continuation.Value = !result; return result; }, work.Add); #if false var enumerator = dispatches.GetEnumerator(); while (enumerator.MoveNext()) { var next = enumerator.Current; var earlier = next.Earlier; if (earlier == null || work.Contains(earlier)) { work.Add(next); enumerator.Remove(); } else { break; } } #endif ProcessDispatches(work, dispatchesPerStmt); } }