Exemplo n.º 1
0
        /// <summary>
        /// Creates a view of the messages identified by the matching parameters and asynchronously fills it in.
        /// View mode can be one of three values:
        ///     Fixed - fixed range based on start and end times
        ///     TailCount - sliding dynamic range that includes the tail of the underlying data based on quantity
        ///     TailRange - sliding dynamic range that includes the tail of the underlying data based on function.
        /// </summary>
        /// <typeparam name="TItem">The type of the message to read.</typeparam>
        /// <param name="viewMode">Mode the view will be created in.</param>
        /// <param name="startTime">Start time of messages to read.</param>
        /// <param name="endTime">End time of messages to read.</param>
        /// <param name="tailCount">Number of messages to included in tail.</param>
        /// <param name="tailRange">Function to determine range included in tail.</param>
        /// <returns>Observable view of data.</returns>
        public ObservableKeyedCache <DateTime, Message <TItem> > .ObservableKeyedView ReadStream <TItem>(
            ObservableKeyedViewMode viewMode,
            DateTime startTime,
            DateTime endTime,
            uint tailCount,
            Func <DateTime, DateTime> tailRange)
        {
            if (viewMode == ObservableKeyedViewMode.Fixed && endTime < startTime)
            {
                throw new ArgumentException("End time must be greater than or equal to start time.", nameof(endTime));
            }
            else if (viewMode == ObservableKeyedViewMode.TailCount && tailCount <= 0)
            {
                throw new ArgumentException("Tail count must be greater than 0", nameof(tailCount));
            }
            else if (viewMode == ObservableKeyedViewMode.TailRange && tailRange == null)
            {
                throw new ArgumentNullException(nameof(tailRange));
            }

            lock (this.ReadRequestsInternal)
            {
                this.ReadRequestsInternal.AddRange(this.ComputeReadRequests(startTime, endTime));
            }

            return((this.data as ObservableKeyedCache <DateTime, Message <TItem> >).GetView(viewMode, startTime, endTime, tailCount, tailRange));
        }
Exemplo n.º 2
0
        /// <inheritdoc />
        public ObservableKeyedCache <DateTime, IntervalData <TItem> > .ObservableKeyedView ReadSummary <TItem>(
            ObservableKeyedViewMode viewMode,
            DateTime startTime,
            DateTime endTime,
            uint tailCount,
            Func <DateTime, DateTime> tailRange)
        {
            if (viewMode == ObservableKeyedViewMode.TailRange)
            {
                // Just read directly from the stream with the same tail range in live mode
                this.ReadStream(tailRange);
            }
            else if (viewMode == ObservableKeyedViewMode.TailCount)
            {
                // We should read enough of the stream to generate the last tailCount intervals. So take the product of our
                // summarization interval and tailCount, and use that interval as the tail range to read from the stream.
                TimeSpan tailInterval = TimeSpan.FromTicks(this.Interval.Ticks * tailCount);
                this.ReadStream(last => last - tailInterval);
            }
            else if (viewMode == ObservableKeyedViewMode.Fixed)
            {
                // Ranges for which we have not yet computed summary data.
                foreach (var range in this.ComputeRangeRequests(startTime, endTime))
                {
                    this.ReadStream(range.Item1, range.Item2);
                }
            }
            else
            {
                throw new NotSupportedException($"Summarization not yet supported in {viewMode} view mode.");
            }

            // Get or create the summary view from the cache
            return(this.GetCachedSummaryView(
                       viewMode,
                       startTime,
                       endTime,
                       tailCount,
                       tailRange) as ObservableKeyedCache <DateTime, IntervalData <TItem> > .ObservableKeyedView);
        }
            /// <summary>
            /// Initializes a new instance of the <see cref="ObservableKeyedView"/> class.
            /// </summary>
            /// <param name="cache">Underlying cache.</param>
            /// <param name="mode">View mode.</param>
            /// <param name="startKey">Start key of the view.</param>
            /// <param name="endKey">End key of the view.</param>
            /// <param name="tailCount">Number of items to include in view.</param>
            /// <param name="tailRange">Tail duration function. Takes last item's key and returns a new startKey.</param>
            internal ObservableKeyedView(ObservableKeyedCache <TKey, TItem> cache, ObservableKeyedViewMode mode, TKey startKey, TKey endKey, uint tailCount, Func <TKey, TKey> tailRange)
            {
                this.cache     = cache;
                this.mode      = mode;
                this.startKey  = startKey;
                this.endKey    = endKey;
                this.tailCount = tailCount;
                this.tailRange = tailRange;

                // Subscribing to cache's DetailedCollectionChanged via WeakEventManager ensures that a strong
                // reference will not be held to the view, allowing it to be collected when no longer referenced.
                WeakEventManager <ObservableKeyedCache <TKey, TItem>, NotifyCollectionChangedEventArgs> .AddHandler(
                    this.cache,
                    nameof(this.cache.DetailedCollectionChanged),
                    this.OnCacheCollectionChanged);

                // update start and end keys
                this.UpdateKeys();

                // update start and end indexes
                this.UpdateIndexes();
            }
Exemplo n.º 4
0
        /// <summary>
        /// Gets a view over the specified time range of the cached summary data.
        /// </summary>
        /// <typeparam name="T">The summary data type.</typeparam>
        /// <param name="streamSource">The stream source indicating which stream to read from.</param>
        /// <param name="viewMode">The view mode, which may be either fixed or live data.</param>
        /// <param name="startTime">The start time of the view range.</param>
        /// <param name="endTime">The end time of the view range.</param>
        /// <param name="interval">The time interval each summary value should cover.</param>
        /// <param name="tailCount">Not yet supported and should be set to zero.</param>
        /// <param name="tailRange">Tail duration function. Computes the view range start time given an end time. Applies to live view mode only.</param>
        /// <returns>A view over the cached summary data that covers the specified time range.</returns>
        public ObservableKeyedCache <DateTime, IntervalData <T> > .ObservableKeyedView ReadSummary <T>(
            StreamSource streamSource,
            ObservableKeyedViewMode viewMode,
            DateTime startTime,
            DateTime endTime,
            TimeSpan interval,
            uint tailCount,
            Func <DateTime, DateTime> tailRange)
        {
            if (startTime > DateTime.MinValue)
            {
                // Extend the start time to include the preceding data point to facilitate continuous plots.
                startTime = this.FindPreviousDataPoint <T>(startTime, interval);
            }

            if (endTime < DateTime.MaxValue)
            {
                // Extend the start time to include the next data point to facilitate continuous plots.
                endTime = this.FindNextDataPoint <T>(endTime, interval);
            }

            return(this.GetOrCreateStreamSummary <T>(streamSource, interval).ReadSummary <T>(viewMode, startTime, endTime, tailCount, tailRange));
        }
        /// <summary>
        /// Gets a dynamic view of the underlying cache based on the parameters given.
        /// </summary>
        /// <param name="mode">View mode.</param>
        /// <param name="startKey">Start key of view.</param>
        /// <param name="endKey">End key of view.</param>
        /// <param name="tailCount">Number of items to include in view.</param>
        /// <param name="tailRange">Tail duration function. Takes last item's key and returns a new startKey.</param>
        /// <returns>An instance of <see cref="ObservableKeyedView"/>.</returns>
        /// <exception cref="ArgumentException"><paramref name="startKey"/> must be less than or equal to <paramref name="endKey"/>.</exception>
        public ObservableKeyedView GetView(ObservableKeyedViewMode mode, TKey startKey, TKey endKey, uint tailCount, Func <TKey, TKey> tailRange)
        {
            if (this.keyComparer.Compare(startKey, endKey) > 0)
            {
                throw new ArgumentException($"startKey ({startKey}) must be less than or equal to endKey ({endKey}).");
            }

            var viewKey = Tuple.Create(startKey, endKey, tailCount, tailRange);
            ObservableKeyedView view = null;

            if (this.views.TryGetValue(viewKey, out WeakReference <ObservableKeyedView> weakView))
            {
                if (weakView.TryGetTarget(out view))
                {
                    return(view);
                }
                else
                {
                    view = new ObservableKeyedView(this, mode, startKey, endKey, tailCount, tailRange);
                    weakView.SetTarget(view);

                    // Sometimes the weak view gets deleted between when we grab it to check
                    // if it has a hard reference and when we actually set the new hard reference
                    // that we just created.  If that happens, then the following code makes sure
                    // the weak view gets put back into the collection.
                    this.views[viewKey] = weakView;
                }
            }
            else
            {
                view     = new ObservableKeyedView(this, mode, startKey, endKey, tailCount, tailRange);
                weakView = new WeakReference <ObservableKeyedView>(view);
                this.views.Add(viewKey, weakView);
            }

            return(view);
        }