/// <summary> /// Positions the reader to the next message from any one of the enabled streams. /// </summary> /// <param name="envelope">The envelope associated with the message read.</param> /// <returns>True if there are more messages, false if no more messages are available.</returns> public bool MoveNext(out Envelope envelope) { envelope = default; do { var hasData = this.AutoOpenAllStreams ? this.messageReader.MoveNext() : this.messageReader.MoveNext(this.enabledStreams); if (!hasData) { if (!PsiStoreMonitor.IsStoreLive(this.Name, this.Path)) { return(false); } bool acquired = false; try { acquired = this.messageReader.DataReady.WaitOne(100); // DataReady is a pulse event, and might be missed } catch (AbandonedMutexException) { // If the writer goes away while we're still reading from the store we'll receive this exception } hasData = this.AutoOpenAllStreams ? this.messageReader.MoveNext() : this.messageReader.MoveNext(this.enabledStreams); if (acquired) { this.messageReader.DataReady.ReleaseMutex(); } if (!hasData) { return(false); } } var messageTime = this.useOriginatingTime ? this.messageReader.Current.OriginatingTime : this.messageReader.Current.CreationTime; if (this.replayInterval.PointIsWithin(messageTime)) { envelope = this.messageReader.Current; this.metadataCache.Resource.Update(); return(true); } if (this.replayInterval.Right < messageTime) { this.CloseStream(this.messageReader.Current.SourceId); } }while (this.AutoOpenAllStreams || this.enabledStreams.Count() > 0); return(false); }
private void Update() { if (this.indexReader == null || !Monitor.TryEnter(this.syncRoot)) { // someone else is updating the list already return; } if (this.indexReader != null) { List <IndexEntry> newList = new List <IndexEntry>(); while (this.indexReader.MoveNext()) { IndexEntry indexEntry; unsafe { this.indexReader.Read((byte *)&indexEntry, sizeof(IndexEntry)); } newList.Add(indexEntry); } if (!PsiStoreMonitor.IsStoreLive(this.name, this.indexReader.Path)) { this.indexReader.Dispose(); this.indexReader = null; } if (newList.Count > 0) { var newIndex = new IndexEntry[this.pageIndex.Length + newList.Count]; Array.Copy(this.pageIndex, newIndex, this.pageIndex.Length); newList.CopyTo(newIndex, this.pageIndex.Length); this.pageIndex = newIndex; } } Monitor.Exit(this.syncRoot); }
public void Update() { if (this.catalogReader == null) { return; } // since the cache is possibly shared by several store readers, // we need to lock before making changes lock (this.syncRoot) { if (this.catalogReader == null || !this.catalogReader.HasMoreData()) { return; } byte[] buffer = new byte[1024]; // will resize as needed var newMetadata = new List <Metadata>(); var newStreamDescriptors = new Dictionary <string, PsiStreamMetadata>(this.streamDescriptors); var newStreamDescriptorsById = new Dictionary <int, PsiStreamMetadata>(this.streamDescriptorsById); while (this.catalogReader.MoveNext()) { var count = this.catalogReader.ReadBlock(ref buffer); var br = new BufferReader(buffer, count); var meta = Metadata.Deserialize(br); if (meta.Kind == MetadataKind.RuntimeInfo) { // we expect this to be first in the file (or completely missing in v0 files) this.runtimeVersion = meta as RuntimeInfo; // Need to review this. The issue was that the RemoteExporter is not writing // out the RuntimeInfo to the stream. This causes the RemoteImporter side of things to // never see a RuntimeInfo metadata object and thus it assumes that the stream is using // version 0.0 of serialization (i.e. non-data-contract version) which causes a mismatch // in the serialization resulting in throw from TypeSchema.ValidateCompatibleWith. This // change fixes the issue. newMetadata.Add(meta); } else { newMetadata.Add(meta); if (meta.Kind == MetadataKind.StreamMetadata) { var sm = meta as PsiStreamMetadata; sm.StoreName = this.name; sm.StorePath = this.path; // the same meta entry will appear multiple times (written on open and on close). // The last one wins. newStreamDescriptors[sm.Name] = sm; newStreamDescriptorsById[sm.Id] = sm; } } } // compute the time ranges this.messageCreationTimeInterval = GetTimeRange(newStreamDescriptors.Values, meta => meta.MessageCreationTimeInterval); this.messageOriginatingTimeInterval = GetTimeRange(newStreamDescriptors.Values, meta => meta.MessageOriginatingTimeInterval); this.streamTimeInterval = GetTimeRange(newStreamDescriptors.Values, meta => meta.StreamTimeInterval); // clean up if the catalog is closed and we really reached the end if (!PsiStoreMonitor.IsStoreLive(this.name, this.path) && !this.catalogReader.HasMoreData()) { this.catalogReader.Dispose(); this.catalogReader = null; } // swap the caches this.streamDescriptors = newStreamDescriptors; this.streamDescriptorsById = newStreamDescriptorsById; // let the registered delegates know about the change if (newMetadata.Count > 0 && this.entriesAdded != null) { this.entriesAdded(newMetadata, this.runtimeVersion); } } }