예제 #1
0
        /// <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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
                }
            }
        }