Example #1
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);
Example #2
0
        /// <inheritdoc/>
        public override void OpenStream(IStreamReader streamReader)
        {
            if (streamReader == null)
            {
                throw new ArgumentNullException(nameof(streamReader));
            }

            if (this.StreamAdapter == null)
            {
                streamReader.OpenStream(this.StreamName, this.OnReceiveData, this.Allocator, this.Deallocator, this.OnReadError);
            }
            else
            {
                dynamic dynStreamAdapter   = this.StreamAdapter;
                dynamic dynAdaptedReceiver = dynStreamAdapter.AdaptReceiver(new Action <T, Envelope>(this.OnReceiveData));
                dynamic dynReadError       = new Action <SerializationException>(this.OnReadError);
                streamReader.OpenStream(this.StreamName, dynAdaptedReceiver, dynStreamAdapter.SourceAllocator, dynStreamAdapter.SourceDeallocator, dynReadError);
            }
        }
Example #3
0
        /// <inheritdoc />
        public void OpenStream(IStreamReader streamReader, bool readIndicesOnly)
        {
            if (streamReader == null)
            {
                throw new ArgumentNullException(nameof(streamReader));
            }

            if (readIndicesOnly)
            {
                if (this.StreamAdapter == null)
                {
                    streamReader.OpenStreamIndex <T>(this.StreamName, this.OnReceiveIndex);
                }
                else
                {
                    var genericOpenStreamIndex = typeof(IStreamReader)
                                                 .GetMethod("OpenStreamIndex", new Type[] { typeof(string), typeof(Action <Func <IStreamReader, T>, Envelope>) })
                                                 .MakeGenericMethod(this.StreamAdapter.SourceType);
                    var receiver = new Action <Func <IStreamReader, T>, Envelope>(this.OnReceiveIndex);
                    genericOpenStreamIndex.Invoke(streamReader, new object[] { this.StreamName, receiver });
                }
            }
            else
            {
                if (this.StreamAdapter == null)
                {
                    streamReader.OpenStream <T>(this.StreamName, this.OnReceiveData, this.Allocator, this.OnReadError);
                }
                else
                {
                    dynamic dynStreamAdapter   = this.StreamAdapter;
                    dynamic dynAdaptedReceiver = dynStreamAdapter.AdaptReceiver(new Action <T, Envelope>(this.OnReceiveData));
                    dynamic dynReadError       = new Action <SerializationException>(this.OnReadError);
                    streamReader.OpenStream(this.StreamName, dynAdaptedReceiver, dynStreamAdapter.Allocator, dynReadError);
                }
            }
        }
        /// <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();
            }
        }