예제 #1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PsiStoreReader"/> class.
 /// This provides a fast way to create a reader,
 /// by reusing the metadata and index already loaded by an existing store reader.
 /// </summary>
 /// <param name="other">Another reader pointing to the same store.</param>
 public PsiStoreReader(PsiStoreReader other)
 {
     this.Name = other.Name;
     this.Path = other.Path;
     this.AutoOpenAllStreams = other.AutoOpenAllStreams;
     this.messageReader      = new MessageReader(PsiStoreCommon.GetDataFileName(this.Name), this.Path);
     this.largeMessageReader = new MessageReader(PsiStoreCommon.GetLargeDataFileName(this.Name), this.Path);
     this.indexCache         = other.indexCache.AddRef();
     this.metadataCache      = other.metadataCache.AddRef();
 }
예제 #2
0
        public MetadataCache(string name, string path, Action <IEnumerable <Metadata>, RuntimeInfo> entriesAdded)
        {
            this.name          = name;
            this.path          = path;
            this.catalogReader = new InfiniteFileReader(path, PsiStoreCommon.GetCatalogFileName(name));
            this.entriesAdded  = entriesAdded;

            // assume v0 for backwards compat. Update will fix this up if the file is newer.
            this.runtimeVersion = new RuntimeInfo(0);
            this.Update();
        }
예제 #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PsiStoreReader"/> class.
        /// </summary>
        /// <param name="name">The name of the application that generated the persisted files, or the root name of the files.</param>
        /// <param name="path">The directory in which the main persisted file resides or will reside, or null to create a volatile data store.</param>
        /// <param name="metadataUpdateHandler">Delegate to call.</param>
        /// <param name="autoOpenAllStreams">Automatically open all streams.</param>
        public PsiStoreReader(string name, string path, Action <IEnumerable <Metadata>, RuntimeInfo> metadataUpdateHandler, bool autoOpenAllStreams = false)
        {
            this.Name = name;
            this.Path = PsiStore.GetPathToLatestVersion(name, path);
            this.AutoOpenAllStreams = autoOpenAllStreams;

            // open the data readers
            this.messageReader      = new MessageReader(PsiStoreCommon.GetDataFileName(this.Name), this.Path);
            this.largeMessageReader = new MessageReader(PsiStoreCommon.GetLargeDataFileName(this.Name), this.Path);
            this.indexCache         = Shared.Create(new PageIndexCache(name, this.Path));
            this.metadataCache      = Shared.Create(new MetadataCache(name, this.Path, metadataUpdateHandler));
        }
예제 #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PsiStoreWriter"/> class.
        /// </summary>
        /// <param name="name">The name of the application that generated the persisted files, or the root name of the files.</param>
        /// <param name="path">The directory in which to create the partition, or null to create a volatile data store.</param>
        /// <param name="createSubdirectory">If true, a numbered sub-directory is created for this store.</param>
        public PsiStoreWriter(string name, string path, bool createSubdirectory = true)
        {
            this.name = name;
            if (path != null)
            {
                int id = 0;
                this.path = System.IO.Path.GetFullPath(path);
                if (createSubdirectory)
                {
                    // if the root directory already exists, look for the next available id
                    if (Directory.Exists(this.path))
                    {
                        var existingIds = Directory.EnumerateDirectories(this.path, this.name + ".????")
                                          .Select(d => d.Split('.').Last())
                                          .Where(
                            n =>
                        {
                            int i;
                            return(int.TryParse(n, out i));
                        })
                                          .Select(n => int.Parse(n));

                        id = (existingIds.Count() == 0) ? 0 : existingIds.Max() + 1;
                    }

                    this.path = System.IO.Path.Combine(this.path, $"{this.name}.{id:0000}");
                }

                if (!Directory.Exists(this.path))
                {
                    Directory.CreateDirectory(this.path);
                }
            }

            this.catalogWriter   = new InfiniteFileWriter(this.path, PsiStoreCommon.GetCatalogFileName(this.name), CatalogExtentSize);
            this.pageIndexWriter = new InfiniteFileWriter(this.path, PsiStoreCommon.GetIndexFileName(this.name), IndexExtentSize);
            this.writer          = new MessageWriter(PsiStoreCommon.GetDataFileName(this.name), this.path);

            // write the first index entry
            this.UpdatePageIndex(0, default(Envelope));
        }
예제 #5
0
        /// <summary>
        /// Indicates whether the specified data store has an active writer.
        /// </summary>
        /// <param name="storeName">The store name.</param>
        /// <param name="storePath">The store path.</param>
        /// <returns>Returns true if there is an active data file writer to this store.</returns>
        public static bool IsStoreLive(string storeName, string storePath)
        {
            if (!Mutex.TryOpenExisting(InfiniteFileWriter.ActiveWriterMutexName(storePath, PsiStoreCommon.GetCatalogFileName(storeName)), out Mutex writerActiveMutex))
            {
                return(false);
            }

            writerActiveMutex.Dispose();
            return(true);
        }
예제 #6
0
        /// <summary>
        /// Creates a stream to write messages to.
        /// </summary>
        /// <param name="streamId">The id of the stream, unique for this store. All messages with this stream id will be written to this stream.</param>
        /// <param name="streamName">The name of the stream. This name can be later used to open the stream for reading.</param>
        /// <param name="indexed">Indicates whether the stream is indexed or not. Indexed streams have a small index entry in the main data file and the actual message body in a large data file.</param>
        /// <param name="typeName">A name identifying the type of the messages in this stream. This is usually a fully-qualified type name or a data contract name, but can be anything that the caller wants.</param>
        /// <returns>The complete metadata for the stream just created.</returns>
        public PsiStreamMetadata OpenStream(int streamId, string streamName, bool indexed, string typeName)
        {
            if (this.metadata.ContainsKey(streamId))
            {
                throw new InvalidOperationException($"The stream id {streamId} has already been registered with this writer.");
            }

            var meta = new PsiStreamMetadata(streamName, streamId, typeName);

            meta.OpenedTime         = Time.GetCurrentTime();
            meta.IsPersisted        = true;
            meta.IsIndexed          = indexed;
            meta.PartitionName      = this.name;
            meta.PartitionPath      = this.path;
            this.metadata[streamId] = meta;
            this.WriteToCatalog(meta);

            // make sure we have a large file if needed
            if (indexed)
            {
                this.largeMessageWriter = this.largeMessageWriter ?? new MessageWriter(PsiStoreCommon.GetLargeDataFileName(this.name), this.path);
            }

            return(meta);
        }
예제 #7
0
 public PageIndexCache(string name, string path)
 {
     this.indexReader = new InfiniteFileReader(path, PsiStoreCommon.GetIndexFileName(name));
 }