/// <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="T">The type of the message to read.</typeparam> /// <param name="streamSource">The stream source indicating which stream to read from.</param> /// <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> internal ObservableKeyedCache <DateTime, Message <T> > .ObservableKeyedView ReadStream <T>( StreamSource streamSource, ObservableKeyedCache <DateTime, Message <T> > .ObservableKeyedView.ViewMode viewMode, DateTime startTime, DateTime endTime, uint tailCount, Func <DateTime, DateTime> tailRange) { return(this.GetOrCreateStreamCacheByStreamSource <T>(streamSource, streamSource.StreamAdapter).ReadStream <T>(viewMode, startTime, endTime, tailCount, tailRange)); }
/// <summary> /// Initializes a new instance of the <see cref="StreamDataProvider{T}"/> class. /// </summary> /// <param name="streamSource">The stream source.</param> public StreamDataProvider(StreamSource streamSource) { this.Allocator = streamSource.Allocator != null ? () => streamSource.Allocator() : null; this.Deallocator = streamSource.Deallocator != null ? t => streamSource.Deallocator(t) : null; this.StreamName = streamSource.StreamName; this.ReadRequestsInternal = new List <ReadRequest>(); this.ReadRequests = new ReadOnlyCollection <ReadRequest>(this.ReadRequestsInternal); }
/// <summary> /// Initializes a new instance of the <see cref="StreamIntervalProvider{T}"/> class. /// </summary> /// <param name="streamSource">The stream source.</param> public StreamIntervalProvider(StreamSource streamSource) : base(streamSource) { this.StreamAdapter = streamSource.StreamAdapter; var itemComparer = Comparer <Message <T> > .Create((m1, m2) => m1.OriginatingTime.CompareTo(m2.OriginatingTime)); this.data = new ObservableKeyedCache <DateTime, Message <T> >(null, itemComparer, m => m.OriginatingTime); this.data.CollectionChanged += this.OnCollectionChanged; this.dataBuffer = new List <Message <T> >(1000); }
/// <summary> /// Initializes a new instance of the <see cref="StreamSummaryManager"/> class. /// </summary> /// <param name="streamSource">A stream source that specifies the store and stream that will be summarized.</param> public StreamSummaryManager(StreamSource streamSource) { if (streamSource == null) { throw new ArgumentNullException(nameof(streamSource)); } this.streamSource = streamSource; this.summaryCaches = new Dictionary <TimeSpan, IStreamSummary>(); this.consumers = new List <Guid>(); }
/// <summary> /// Initializes a new instance of the <see cref="StreamValueProvider{T}"/> class. /// </summary> /// <param name="streamSource">The stream source.</param> public StreamValueProvider(StreamSource streamSource) : base(streamSource) { this.indexView = null; this.publishers = new Dictionary <RelativeTimeInterval, List <IStreamValuePublisher <TSource> > >(); var indexComparer = Comparer <MessageIndex <TSource> > .Create((i1, i2) => i1.OriginatingTime.CompareTo(i2.OriginatingTime)); this.index = new ObservableKeyedCache <DateTime, MessageIndex <TSource> >(null, indexComparer, ie => ie.OriginatingTime); this.indexBuffer = new List <MessageIndex <TSource> >(1000); }
/// <summary> /// Gets or creates a stream value provider for a specified stream source. /// </summary> /// <typeparam name="T">The type of messages in the stream.</typeparam> /// <param name="streamSource">The stream source.</param> /// <returns>The stream value provider.</returns> internal IStreamValueProvider GetOrCreateStreamValueProvider <T>(StreamSource streamSource) { var streamValueProvider = this.GetStreamValueProviderOrDefault(streamSource.StreamName); if (streamValueProvider == null) { streamValueProvider = new StreamValueProvider <T>(streamSource); (streamValueProvider as StreamDataProvider <T>).StreamReadError += this.OnStreamReadError; lock (this.streamDataProviders) { this.streamDataProviders.Add(streamValueProvider); } } return(streamValueProvider); }
/// <summary> /// Gets or creates a stream interval provider for a specified stream source. /// </summary> /// <typeparam name="T">The type of messages in the stream.</typeparam> /// <param name="streamSource">The stream source.</param> /// <returns>The stream interval provider.</returns> internal IStreamIntervalProvider GetOrCreateStreamIntervalProvider <T>(StreamSource streamSource) { var streamIntervalProvider = this.GetStreamIntervalProviderOrDefault(streamSource.StreamName, streamSource.StreamAdapter); if (streamIntervalProvider == null) { streamIntervalProvider = new StreamIntervalProvider <T>(streamSource); streamIntervalProvider.NoRemainingSubscribers += this.StreamDataProvider_NoRemainingSubscribers; (streamIntervalProvider as StreamDataProvider <T>).StreamReadError += this.OnStreamReadError; lock (this.streamDataProviders) { this.streamDataProviders.Add(streamIntervalProvider); } } return(streamIntervalProvider); }
private IStreamSummary GetOrCreateStreamSummary <T>(StreamSource streamSource, TimeSpan interval) { // Get the summary cache if it exists. IStreamSummary summaryCache = this.GetStreamSummaryOrDefault(interval); // A summary cache with the required interval does not exist, so create it now. if (summaryCache == null) { summaryCache = typeof(StreamSummary <,>) .MakeGenericType(streamSource.Summarizer.SourceType, streamSource.Summarizer.DestinationType) .GetConstructor(new Type[] { typeof(StreamSource), typeof(TimeSpan), typeof(uint) }) .Invoke(new object[] { streamSource, interval, DefaultCacheCapacity }) as IStreamSummary; this.summaryCaches[interval] = summaryCache ?? throw new InvalidOperationException("Unable to create instance of summary cache"); } return(summaryCache); }
/// <summary> /// Initializes a new instance of the <see cref="StreamSummary{TSource, TDestination}"/> class. /// </summary> /// <param name="streamSource">Stream source indicating which stream to summarize.</param> /// <param name="interval">The time interval over which summary <see cref="IntervalData"/> values are calculated.</param> /// <param name="maxCacheSize">The maximum amount of data to cache before purging older summarized data.</param> public StreamSummary(StreamSource streamSource, TimeSpan interval, uint maxCacheSize) { this.streamSource = streamSource; this.interval = interval; this.maxCacheSize = maxCacheSize; this.summaryDataBuffer = new List <List <IntervalData <TDestination> > >(); this.keySelector = s => Summarizer <TSource, TDestination> .GetIntervalStartTime(s.OriginatingTime, interval); this.itemComparer = Comparer <IntervalData <TDestination> > .Create((r1, r2) => this.keySelector(r1).CompareTo(this.keySelector(r2))); this.summaryCache = new ObservableKeyedCache <DateTime, IntervalData <TDestination> >(null, this.itemComparer, this.keySelector); this.activeStreamViews = new Dictionary <Tuple <DateTime, DateTime, uint, Func <DateTime, DateTime> >, ObservableKeyedCache <DateTime, Message <TSource> > .ObservableKeyedView>(); this.cachedSummaryViews = new Dictionary <Tuple <DateTime, DateTime, uint, Func <DateTime, DateTime> >, ObservableKeyedCache <DateTime, IntervalData <TDestination> > .ObservableKeyedView>(); // Cache the summarizer (cast to the correct type) to call its methods later on without dynamic binding this.summarizer = this.streamSource.Summarizer as ISummarizer <TSource, TDestination>; }
/// <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, ObservableKeyedCache <DateTime, IntervalData <T> > .ObservableKeyedView.ViewMode 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.GetOrCreateSummaryCache(streamSource, interval).ReadSummary <T>(viewMode, startTime, endTime, tailCount, tailRange)); }
/// <summary> /// Performs a series of updates to the messages in a stream. /// </summary> /// <typeparam name="T">The type of the messages in the stream.</typeparam> /// <param name="streamSource">The stream source indicating which stream to read from.</param> /// <param name="updates">A collection of updates to perform.</param> internal void UpdateStream <T>(StreamSource streamSource, IEnumerable <StreamUpdate <T> > updates) => this.GetStreamIntervalProviderOrDefault(streamSource.StreamName, streamSource.StreamAdapter) .UpdateStream <T>(updates);
/// <summary> /// Gets the time of the nearest message to a specified time, on a specified stream. /// </summary> /// <param name="streamSource">The stream source specifying the stream of interest.</param> /// <param name="time">The time to find the nearest message to.</param> /// <param name="nearestMessageType">The type of nearest message to find.</param> /// <returns>The time of the nearest message, if one is found or null otherwise.</returns> internal DateTime?GetTimeOfNearestMessage(StreamSource streamSource, DateTime time, NearestMessageType nearestMessageType) => this.GetStreamProviderOrDefault(streamSource.StreamName) .GetTimeOfNearestMessage(time, nearestMessageType);
/// <summary> /// Performs a series of updates to the messages in a stream. /// </summary> /// <typeparam name="T">The type of the messages in the stream.</typeparam> /// <param name="streamSource">The stream source indicating which stream to read from.</param> /// <param name="updates">A collection of updates to perform.</param> internal void UpdateStream <T>(StreamSource streamSource, IEnumerable <StreamUpdate <T> > updates) { this.GetExistingStreamCache(streamSource, streamSource.StreamAdapter).UpdateStream <T>(updates); }
/// <summary> /// Gets the supplemental metadata for a stream. /// </summary> /// <typeparam name="TSupplementalMetadata">The type of the supplemental metadata.</typeparam> /// <param name="streamSource">The stream source indicating which stream to read from.</param> /// <returns>The supplemental metadata for the stream.</returns> internal TSupplementalMetadata GetSupplementalMetadata <TSupplementalMetadata>(StreamSource streamSource) { return(this.streamReader.GetSupplementalMetadata <TSupplementalMetadata>(streamSource.StreamName)); }