/// <summary>
        /// Reads instant data from the stream at the given cursor time and pushes it to all registered adapting data providers.
        /// </summary>
        /// <param name="reader">The simple reader that will read the data.</param>
        /// <param name="cursorTime">The cursor time at which to read the data.</param>
        /// <param name="indexCache">The stream reader's index cache.</param>
        public void ReadInstantData(ISimpleReader reader, DateTime cursorTime, ObservableKeyedCache <DateTime, IndexEntry> indexCache)
        {
            // Get the index of the data, given the cursor time
            int index = IndexHelper.GetIndexForTime(cursorTime, indexCache?.Count ?? 0, (idx) => indexCache[idx].OriginatingTime, this.CursorEpsilon);

            T          data       = default;
            IndexEntry indexEntry = default;

            if (index >= 0)
            {
                // Get the index entry
                indexEntry = indexCache[index];

                // Read the data
                data = reader.Read <T>(indexEntry);
            }

            // Notify each adapting data provider of the new data
            foreach (IAdaptingInstantDataProvider <T> adaptingInstantDataProvider in this.dataProviders.ToList())
            {
                adaptingInstantDataProvider.PushData(data, indexEntry);
            }

            // Release the reference to the local copy of the data if it's shared
            if (this.isSharedType && data != null)
            {
                (data as IDisposable).Dispose();
            }
        }
        private bool AnnotationIntersectsWith(TimeInterval timeInterval)
        {
            // If there's no annotations at all, we're done
            if ((this.Data == null) || (this.Data.Count <= 0))
            {
                return(false);
            }

            // Find the nearest annotation to the left edge of the interval
            int index = IndexHelper.GetIndexForTime(timeInterval.Left, this.Data.Count, (idx) => this.Data[idx].Data.Interval.Right, SnappingBehavior.Nearest);

            // Check if the annotation intersects with the interval, then keep walking to the right until
            // we find an annotation within the interval or we go past the right hand side of the interval.
            while (index < this.Data.Count)
            {
                TimeIntervalAnnotation annotation = this.Data[index].Data;

                // Check if the annotation intersects with the interval
                if (timeInterval.IntersectsWith(annotation.Interval))
                {
                    return(true);
                }

                // Check if the annotation is completely to the right of the interval
                if (timeInterval.Right <= annotation.Interval.Left)
                {
                    return(false);
                }

                index++;
            }

            return(false);
        }
示例#3
0
        /// <summary>
        /// Reads instant data from the stream at the given cursor time and pushes it to all registered adapting data providers.
        /// </summary>
        /// <param name="reader">The simple reader that will read the data.</param>
        /// <param name="cursorTime">The cursor time at which to read the data.</param>
        /// <param name="indexCache">The stream reader's index cache.</param>
        public void ReadInstantData(ISimpleReader reader, DateTime cursorTime, ObservableKeyedCache <DateTime, IndexEntry> indexCache)
        {
            // Get the index of the data, given the cursor time
            int index = IndexHelper.GetIndexForTime(cursorTime, indexCache?.Count ?? 0, (idx) => indexCache[idx].OriginatingTime, this.CursorEpsilon);

            T          data       = default;
            IndexEntry indexEntry = default;

            if (index >= 0)
            {
                // Get the index entry
                indexEntry = indexCache[index];

                // Read the data
                data = reader.Read <T>(indexEntry);
            }

            // Notify all registered adapting data providers of the new data.  If the data is Shared<T> then perform a deep clone
            // (which resolves to an AddRef() for this type) for each provider we call.  The providers are responsible for releasing
            // their reference to the data once they're done with it.
            if (this.isSharedType && data != null)
            {
                Parallel.ForEach(this.dataProviders.ToList(), provider => provider.PushData(data.DeepClone <T>(), indexEntry));

                // Release the reference to the local copy of the data
                (data as IDisposable).Dispose();
            }
            else
            {
                Parallel.ForEach(this.dataProviders.ToList(), provider => provider.PushData(data, indexEntry));
            }
        }
示例#4
0
        /// <inheritdoc/>
        public void ReadAndPublishStreamValue(IStreamReader streamReader, DateTime dateTime)
        {
            foreach (var epsilonTimeInterval in this.publishers.Keys)
            {
                // Get the index of the data, given the cursor time, and the epsilon interval.
                int index = IndexHelper.GetIndexForTime(dateTime, epsilonTimeInterval, this.index?.Count ?? 0, (idx) => this.index[idx].OriginatingTime);

                if (index >= 0)
                {
                    // Get the index entry
                    var indexedStreamReaderThunk = this.index[index];

                    // Read the data (this allocates)
                    var data = indexedStreamReaderThunk.Read(streamReader);

                    // Publish the value
                    foreach (var publisher in this.publishers[epsilonTimeInterval])
                    {
                        publisher.PublishValue(true, data, indexedStreamReaderThunk.OriginatingTime, indexedStreamReaderThunk.CreationTime);
                    }

                    // Deallocate to control the lifetime of the read object
                    this.Deallocator?.Invoke(data);
                }
                else
                {
                    // Cache miss, attempt to seek directly. The cache miss could happen because the
                    // the stream index data structure is being populated, or because the epsilon interval
                    // is set such that no data point is found. In either case, a direct read is
                    // attempted.
                    streamReader.Seek(dateTime + epsilonTimeInterval, true);
                    streamReader.OpenStream(
                        this.StreamName,
                        (data, envelope) =>
                    {
                        foreach (var publisher in this.publishers[epsilonTimeInterval])
                        {
                            publisher.PublishValue(true, data, envelope.OriginatingTime, envelope.CreationTime);
                        }
                    },
                        this.Allocator,
                        this.Deallocator);

                    // This will force the read of the next message. If a message within the seek
                    // constraints is found, the delegate passed to OpenStream above is executed
                    // to capture the data. If no message exists in that specified seek interval
                    // the delegate does not execute and found below becomes false.
                    var found = streamReader.MoveNext(out var envelope);

                    // If no message was found
                    if (!found)
                    {
                        // Then signal the data providers that to message is available
                        foreach (var publisher in this.publishers[epsilonTimeInterval])
                        {
                            publisher.PublishValue(false, default, default, default);
示例#5
0
        /// <inheritdoc />
        public DateTime?GetOriginatingTimeOfNearestInstantMessage(DateTime time)
        {
            int index = IndexHelper.GetIndexForTime(time, this.instantIndexView.Count, (idx) => this.instantIndexView[idx].OriginatingTime, SnappingBehavior.Nearest);

            if (index >= 0)
            {
                return(this.instantIndexView[index].OriginatingTime);
            }

            return(null);
        }
        /// <summary>
        /// Reads instant data from the stream at the given cursor time and pushes it to all registered adapting data providers.
        /// </summary>
        /// <param name="streamReader">The stream reader that will read the data.</param>
        /// <param name="cursorTime">The cursor time at which to read the data.</param>
        /// <param name="streamCache">The stream reader's cache.</param>
        public void ReadInstantData(IStreamReader streamReader, DateTime cursorTime, ObservableKeyedCache <DateTime, StreamCacheEntry> streamCache)
        {
            // Get the index of the data, given the cursor time
            int index = IndexHelper.GetIndexForTime(cursorTime, streamCache?.Count ?? 0, (idx) => streamCache[idx].OriginatingTime, this.CursorEpsilon);

            T data = default;
            StreamCacheEntry cacheEntry = default;

            if (index >= 0)
            {
                // Get the index entry
                cacheEntry = streamCache[index];

                // Read the data
                data = cacheEntry.Read <T>(streamReader);
            }
            else
            {
                // cache miss, attempt to seek directly while the cache is presumably being populated
                streamReader.Seek(cursorTime + this.CursorEpsilon, true);
                streamReader.OpenStream <T>(this.streamName, (m, e) =>
                {
                    cacheEntry = new StreamCacheEntry(null, e.CreationTime, e.OriginatingTime);
                    data       = m;
                });
                streamReader.MoveNext(out var envelope);
            }

            // Notify each adapting data provider of the new data
            foreach (IAdaptingInstantDataProvider <T> adaptingInstantDataProvider in this.dataProviders.ToList())
            {
                adaptingInstantDataProvider.PushData(data, cacheEntry);
            }

            // Release the reference to the local copy of the data if it's shared
            if (this.isSharedType && data != null)
            {
                (data as IDisposable).Dispose();
            }
        }
        private bool AnnotationIntersectsWith(TimeInterval timeInterval)
        {
            // If there's no annotations at all, we're done
            if ((this.Data == null) || (this.Data.Count <= 0))
            {
                return(false);
            }

            // Find the nearest annotation to the left edge of the interval
            int index = IndexHelper.GetIndexForTime(timeInterval.Left, this.Data.Count, (idx) => this.Data[idx].Data.Interval.Right, NearestMessageType.Nearest);

            // Check if the annotation intersects with the interval, then keep walking to the right until
            // we find an annotation within the interval or we go past the right hand side of the interval.
            while (index < this.Data.Count)
            {
                TimeIntervalAnnotation annotation = this.Data[index].Data;

                // Check if the annotation is completely to the left of the interval
                // NOTE: By default time intervals are inclusive of their endpoints, so abutting time intervals will
                // test as intersecting. Use a non-inclusive time interval so that we can let annotations abut.
                if (timeInterval.IntersectsWith(new TimeInterval(annotation.Interval.Left, false, annotation.Interval.Right, false)))
                {
                    return(true);
                }

                // Check if the annotation is completely to the right of the interval
                if (timeInterval.Right <= annotation.Interval.Left)
                {
                    return(false);
                }

                index++;
            }

            return(false);
        }
示例#8
0
        /// <inheritdoc/>
        public override DateTime?GetTimeOfNearestMessage(DateTime time, NearestMessageType snappingBehavior)
        {
            int index = IndexHelper.GetIndexForTime(time, this.data.Count, (idx) => this.data[idx].OriginatingTime, snappingBehavior);

            return((index >= 0) ? this.data[index].OriginatingTime : null);
        }
示例#9
0
 /// <inheritdoc/>
 protected override int GetIndexForTime(DateTime currentTime, int count, Func <int, DateTime> timeAtIndex)
 {
     return(IndexHelper.GetIndexForTime(currentTime, count, timeAtIndex));
 }