/// <summary> /// Initializes a new instance of the <see cref="DataStoreReader"/> class. /// </summary> /// <param name="storeName">Store name to read.</param> /// <param name="storePath">Store path to read.</param> /// <param name="simpleReaderType">Simple reader type.</param> public DataStoreReader(string storeName, string storePath, Type simpleReaderType) { this.simpleReader = (ISimpleReader)simpleReaderType.GetConstructor(new Type[] { }).Invoke(new object[] { }); this.simpleReader.OpenStore(storeName, storePath); this.executionContexts = new List <ExecutionContext>(); this.streamReaders = new List <IStreamReader>(); }
/// <summary> /// Reads a single message from a stream identified by a stream binding and an index entry. /// </summary> /// <typeparam name="T">The type of the message to read.</typeparam> /// <param name="streamBinding">The stream binding inidicating which stream to read from.</param> /// <param name="indexEntry">The index entry indicating which message to read.</param> /// <returns>The message that was read.</returns> public T Read <T>(StreamBinding streamBinding, IndexEntry indexEntry) { using (ISimpleReader reader = this.simpleReader.OpenNew()) { return(this.GetStreamReader <T>(streamBinding, true).Read <T>(reader, indexEntry)); } }
/// <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(); } }
/// <inheritdoc /> public void Dispose() { // cancel all stream readers this.streamReaders?.ForEach(sr => sr.Cancel()); // dispose and clean up execution contexts this.executionContexts.ForEach(ec => { try { ec.ReadAllTokenSource.Cancel(); ec.ReadAllTask.Wait(); } catch (AggregateException) { } ec.Reader.Dispose(); ec.ReadAllTask.Dispose(); ec.ReadAllTokenSource.Dispose(); }); this.executionContexts.Clear(); this.executionContexts = null; // dispose all stream readers this.streamReaders?.ForEach(sr => sr.Dispose()); this.streamReaders?.Clear(); this.streamReaders = null; // dispose of simple reader this.simpleReader?.Dispose(); this.simpleReader = 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="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)); } }
/// <inheritdoc /> public void ReadInstantData(ISimpleReader reader, DateTime cursorTime) { // Forward the call to all the instant stream readers foreach (EpsilonInstantStreamReader <T> instantStreamReader in this.GetInstantStreamReaderList()) { instantStreamReader.ReadInstantData(reader, cursorTime, this.index); } }
/// <summary> /// Called to ask the reader to read the data for all instant streams. /// </summary> /// <param name="cursorTime">The time of the visualization container's cursor.</param> internal void ReadInstantData(DateTime cursorTime) { using (ISimpleReader reader = this.simpleReader.OpenNew()) { foreach (IStreamReader streamReader in this.streamReaders.ToList()) { if (streamReader.HasInstantStreamReaders) { streamReader.ReadInstantData(reader, cursorTime); } } } }
/// <inheritdoc /> public TDest Read <TDest>(ISimpleReader reader, IndexEntry indexEntry) { if (this.StreamBinding.StreamAdapter == null) { return(reader.Read <TDest>(indexEntry)); } else { var genericRead = typeof(ISimpleReader) .GetMethod("Read", new Type[] { typeof(IndexEntry) }) .MakeGenericMethod(this.StreamBinding.StreamAdapter.SourceType); var src = genericRead.Invoke(reader, new object[] { indexEntry }); var adaptData = typeof(StreamAdapter <,>) .MakeGenericType(this.StreamBinding.StreamAdapter.SourceType, this.StreamBinding.StreamAdapter.DestinationType) .GetMethod("AdaptData"); return((TDest)adaptData.Invoke(this.StreamBinding.StreamAdapter, new object[] { src })); } }
/// <inheritdoc /> public void OpenStream(ISimpleReader reader, bool readIndicesOnly) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (readIndicesOnly) { if (this.streamAdapter == null) { reader.OpenStreamIndex <T>(this.StreamName, this.OnReceiveIndex); } else { var genericOpenStreamIndex = typeof(ISimpleReader) .GetMethod("OpenStreamIndex", new Type[] { typeof(string), typeof(Action <IndexEntry, Envelope>) }) .MakeGenericMethod(this.streamAdapter.SourceType); var receiver = new Action <IndexEntry, Envelope>(this.OnReceiveIndex); genericOpenStreamIndex.Invoke(reader, new object[] { this.StreamName, receiver }); } } else { if (this.streamAdapter == null) { reader.OpenStream <T>(this.StreamName, this.OnReceiveData, this.Allocator); } else { dynamic dynStreamAdapter = this.streamAdapter; dynamic dynAdaptedReceiver = dynStreamAdapter.AdaptReceiver(new Action <T, Envelope>(this.OnReceiveData)); reader.OpenStream(this.StreamName, dynAdaptedReceiver, dynStreamAdapter.Allocator); } } }