1405 lines · 48.8 KB · C#
RawDownload
//******************************************************************************************************//  IsamDataFileBase.cs - Gbtc////  Copyright © 2012, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may//  not use this file except in compliance with the License. You may obtain a copy of the License at:////      http://www.opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  03/08/2007 - Pinal C. Patel//       Original version of source code generated.//  11/30/2007 - Pinal C. Patel//       Modified the "design time" check in EndInit() method to use LicenseManager.UsageMode property//       instead of DesignMode property as the former is more accurate than the latter.//  09/19/2008 - J. Ritchie Carroll//       Converted to C#.//  10/28/2008 - Pinal C. Patel//       Edited code comments.//  12/04/2008 - J. Ritchie Carroll//       Modified class an example to use new ISupportBinaryImage.//  05/12/2009 - Pinal C. Patel//       Optimized Read() for better memory management by using "yield return".//  05/19/2009 - Pinal C. Patel//       Implemented the IProvideStatus interface.//  07/02/2009 - Pinal C. Patel//       Modified state alternating properties to reopen the file when changed.//  08/10/2009 - Pinal C. Patel//       Modified Write() to write empty intermediate records that are missing to avoid garbage data //       for the missing intermediate records when records are being written to disk directly.//  09/14/2009 - Stephen C. Wills//       Added new header and license agreement.//  09/16/2009 - Pinal C. Patel//       Modified Save() to flush buffered data to disk.//       Removed MinimumRecordCount property - not very useful.//  09/17/2009 - Pinal C. Patel//       Added exception handling to event handlers.//  12/04/2009 - Pinal C. Patel//       Fixed thread synchronization issue in ReadFromDisk().//  04/07/2011 - Pinal C. Patel//       Removed inheritance from Component class to allow for serialization.//  11/23/2011 - J. Ritchie Carroll//       Modified to support buffer optimized ISupportBinaryImage.//  12/06/2011 - Pinal C. Patel//       Updated to instantiate a FileSystemWatcher object that watches for changes to the file content //       only  if needed to avoid a issue introduced in .NET 4.0 that causes memory leak.//  12/14/2012 - Starlynn Danyelle Gilliam//       Modified Header.////****************************************************************************************************** using System;using System.Collections.Generic;using System.Configuration;using System.IO;using System.Text;using System.Threading;using System.Timers;using System.Xml.Serialization;using GSF.Configuration;using GSF.Parsing;using Timer = System.Timers.Timer; namespace GSF.IO{    /// <summary>    /// An abstract class that defines the read/write capabilities for ISAM (Indexed Sequential Access Method) file.    /// </summary>    /// <typeparam name="T">    /// <see cref="Type"/> of the records the file contains. This <see cref="Type"/> must implement the <see cref="ISupportBinaryImage"/> interface.    /// </typeparam>    /// <remarks>    /// <para>    /// This ISAM implementation keeps all the records in memory, so it may not be suitable for very large files. Since data is stored    /// in memory using a list, the maximum number of possible supported records will be 2,147,483,647 (i.e., Int32.MaxValue).    /// </para>    /// <para>    /// See <a href="http://en.wikipedia.org/wiki/ISAM" target="_blank">http://en.wikipedia.org/wiki/ISAM</a> for more information on ISAM files.    /// </para>    /// </remarks>    /// <example>    /// This example shows a sample implementation of <see cref="IsamDataFileBase{T}"/>:    /// <code>    /// using System;    /// using System.Text;    /// using GSF;    /// using GSF.IO;    /// using GSF.Parsing;    ///     /// class Program    /// {    ///     static void Main(string[] args)    ///     {    ///         // Create a few test records.    ///         TestIsamFileRecord r1 = new TestIsamFileRecord(1);    ///         r1.Name = "TestRecord1";    ///         r1.Value = double.MinValue;    ///         r1.Description = "Test record with minimum double value";    ///         TestIsamFileRecord r2 = new TestIsamFileRecord(2);    ///         r2.Name = "TestRecord2";    ///         r2.Value = double.MaxValue;    ///         r2.Description = "Test record with maximum double value";    ///     ///         // Open ISAM file.    ///         TestIsamFile testFile = new TestIsamFile();    ///         testFile.FileName = "TestIsamFile.dat";    ///         testFile.Open();    ///     ///         // Write test records.    ///         testFile.Write(r1.Index, r1);    ///         testFile.Write(r2.Index, r2);    ///     ///         // Read test records.    ///         Console.WriteLine(testFile.Read(1));    ///         Console.WriteLine(testFile.Read(2));    ///     ///         // Close ISAM file.    ///         testFile.Close();    ///     ///         Console.ReadLine();    ///     }    /// }    ///     /// class TestIsamFile : IsamDataFileBase&lt;TestIsamFileRecord&gt;    /// {    ///     /// <summary>    ///     /// Size of a single file record.    ///     /// </summary>    ///     protected override int GetRecordSize()    ///     {    ///         return TestIsamFileRecord.RecordLength;    ///     }    ///     ///     /// <summary>    ///     /// Creates a new empty file record.    ///     /// </summary>    ///     protected override TestIsamFileRecord CreateNewRecord(int id)    ///     {    ///         return new TestIsamFileRecord(id);    ///     }    /// }    ///     /// class TestIsamFileRecord : ISupportBinaryImage    /// {    ///     private int m_index;    ///     private string m_name;                  // 20  * 1 =  20    ///     private double m_value;                 // 1   * 8 =   8    ///     private string m_description;           // 100 * 1 = 100    ///         ///     public const int RecordLength = 128;    // Total   = 128    ///     ///     public TestIsamFileRecord(int recordIndex)    ///     {    ///         m_index = recordIndex;    ///             ///         Name = string.Empty;    ///         Value = double.NaN;    ///         Description = string.Empty;    ///     }    ///     ///     /// <summary>    ///     /// 1-based index of the record.    ///     /// </summary>    ///     public int Index    ///     {    ///         get { return m_index; }    ///     }    ///     ///     /// <summary>    ///     /// Name of the record.    ///     /// </summary>    ///     public string Name    ///     {    ///         get { return m_name; }    ///         set { m_name = value.TruncateRight(20).PadRight(20); }    ///     }    ///     ///     /// <summary>    ///     /// Value of the record.    ///     /// </summary>    ///     public double Value    ///     {    ///         get { return m_value; }    ///         set { m_value = value; }    ///     }    ///     ///     /// <summary>    ///     /// Description of the record.    ///     /// </summary>    ///     public string Description    ///     {    ///         get { return m_description; }    ///         set { m_description = value.TruncateRight(100).PadRight(100); }    ///     }    ///     ///     /// <summary>    ///     /// Serialized record length.    ///     /// </summary>    ///     public int BinaryLength    ///     {    ///         get { return RecordLength; }    ///     }    ///     ///     /// <summary>    ///     /// Serialized record data.    ///     /// </summary>    ///     public byte[] BinaryImage    ///     {    ///         get    ///         {    ///             // Serialize TestIsamFileRecord into byte array.    ///             byte[] image = new byte[RecordLength];    ///             Buffer.BlockCopy(Encoding.ASCII.GetBytes(Name), 0, image, 0, 20);    ///             Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, image, 20, 8);    ///             Buffer.BlockCopy(Encoding.ASCII.GetBytes(Description), 0, image, 28, 100);    ///     ///             return image;    ///         }    ///     }    ///     ///     /// <summary>    ///     /// Deserializes the record.    ///     /// </summary>    ///     public int Initialize(byte[] binaryImage, int startIndex, int length)    ///     {    ///         if (length &gt;= RecordLength)    ///         {    ///             // Deserialize byte array into TestIsamFileRecord.    ///             Name = Encoding.ASCII.GetString(binaryImage, startIndex, 20);    ///             Value = BitConverter.ToDouble(binaryImage, startIndex + 20);    ///             Description = Encoding.ASCII.GetString(binaryImage, startIndex + 28, 100);    ///         }    ///         else    ///             throw new InvalidOperationException("Invalid record size, not enough data to deserialize record");     ///     ///         return RecordLength;    ///     }    ///     ///     /// <summary>    ///     /// String representation of the record.    ///     /// </summary>    ///     public override string ToString()    ///     {    ///         return string.Format("Name: {0}, Value: {1}, Description: {2}", Name, Value, Description);    ///     }    /// }    /// </code>    /// </example>    public abstract class IsamDataFileBase<T> : ISupportLifecycle, IProvideStatus, IPersistSettings where T : ISupportBinaryImage    {        #region [ Members ]         // Constants         /// <summary>        /// Specifies the default value for the <see cref="FileName"/> property.        /// </summary>        public const string DefaultFileName = "IsamDataFile.dat";         /// <summary>        /// Specifies the default value for the <see cref="FileAccessMode"/> property.        /// </summary>        public const FileAccess DefaultFileAccessMode = FileAccess.ReadWrite;         /// <summary>        /// Specifies the default value for the <see cref="AutoSaveInterval"/> property.        /// </summary>        public const int DefaultAutoSaveInterval = -1;         /// <summary>        /// Specifies the default value for the <see cref="LoadOnOpen"/> property.        /// </summary>        public const bool DefaultLoadOnOpen = false;         /// <summary>        /// Specifies the default value for the <see cref="SaveOnClose"/> property.        /// </summary>        public const bool DefaultSaveOnClose = false;         /// <summary>        /// Specifies the default value for the <see cref="ReloadOnModify"/> property.        /// </summary>        public const bool DefaultReloadOnModify = false;         /// <summary>        /// Specifies the default value for the <see cref="PersistSettings"/> property.        /// </summary>        public const bool DefaultPersistSettings = false;         /// <summary>        /// Specifies the default value for the <see cref="SettingsCategory"/> property.        /// </summary>        public const string DefaultSettingsCategory = "IsamDataFile";         // Events         /// <summary>        /// Occurs when data is being read from disk into memory.        /// </summary>        public event EventHandler DataLoading;         /// <summary>        /// Occurs when data has been read from disk into memory.        /// </summary>        public event EventHandler DataLoaded;         /// <summary>        /// Occurs when data is being saved from memory onto disk.        /// </summary>        public event EventHandler DataSaving;         /// <summary>        /// Occurs when data has been saved from memory onto disk.        /// </summary>        public event EventHandler DataSaved;         /// <summary>        /// Occurs when file data on the disk is modified.        /// </summary>        public event EventHandler FileModified;         /// <summary>        /// Occurs when the class has been disposed.        /// </summary>        public event EventHandler Disposed;         // Fields        private string m_fileName;        private FileAccess m_fileAccessMode;        private int m_autoSaveInterval;        private bool m_loadOnOpen;        private bool m_saveOnClose;        private bool m_reloadOnModify;        private bool m_persistSettings;        private string m_settingsCategory;        private List<T> m_fileRecords;        private byte[] m_recordBuffer;        private FileStream m_fileData;        private readonly object m_fileDataLock;        private readonly ManualResetEventSlim m_loadWaitHandle;        private readonly ManualResetEventSlim m_saveWaitHandle;        private readonly Timer m_autoSaveTimer;        private SafeFileWatcher m_fileWatcher;        private bool m_disposed;        private bool m_initialized;         #endregion         #region [ Constructors ]         /// <summary>        /// Initializes a new instance of the <see cref="IsamDataFileBase{T}"/> class.        /// </summary>        protected IsamDataFileBase()        {            m_fileName = DefaultFileName;            m_fileAccessMode = DefaultFileAccessMode;            m_autoSaveInterval = DefaultAutoSaveInterval;            m_loadOnOpen = DefaultLoadOnOpen;            m_saveOnClose = DefaultSaveOnClose;            m_reloadOnModify = DefaultReloadOnModify;            m_persistSettings = DefaultPersistSettings;            m_settingsCategory = DefaultSettingsCategory;            m_loadWaitHandle = new ManualResetEventSlim(true);            m_saveWaitHandle = new ManualResetEventSlim(true);            m_fileDataLock = new object();             m_autoSaveTimer = new Timer();            m_autoSaveTimer.Elapsed += m_autoSaveTimer_Elapsed;        }         /// <summary>        /// Releases the unmanaged resources before the file is reclaimed by <see cref="GC"/>.        /// </summary>        ~IsamDataFileBase()        {            Dispose(false);        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets or sets the name of the file.        /// </summary>        /// <remarks>        /// Changing the <see cref="FileName"/> when the file is open will cause the file to be re-opened.        /// </remarks>        public virtual string FileName        {            get            {                return m_fileName;            }            set            {                if (string.IsNullOrEmpty(value))                    throw new ArgumentNullException("value");                 m_fileName = value;                ReOpen();            }        }         /// <summary>        /// Gets or sets the <see cref="FileAccess"/> value to use when opening the file.        /// </summary>        public FileAccess FileAccessMode        {            get            {                return m_fileAccessMode;            }            set            {                m_fileAccessMode = value;                ReOpen();            }        }         /// <summary>        /// Gets or sets the interval in milliseconds at which the records loaded in memory are to be persisted to disk.        /// </summary>        /// <remarks>        /// <see cref="AutoSaveInterval"/> will be effective only if records have been loaded in memory either manually         /// by calling the <see cref="Load()"/> method or automatically by settings <see cref="LoadOnOpen"/> to true.        /// </remarks>        public int AutoSaveInterval        {            get            {                return m_autoSaveInterval;            }            set            {                m_autoSaveInterval = value;                ReOpen();            }        }         /// <summary>        /// Gets or sets a boolean value that indicates whether records are to be loaded automatically in memory when         /// the file is opened.        /// </summary>        public bool LoadOnOpen        {            get            {                return m_loadOnOpen;            }            set            {                m_loadOnOpen = value;                ReOpen();            }        }         /// <summary>        /// Gets or sets a boolean value that indicates whether records loaded in memory are to be persisted to disk         /// when the file is closed.        /// </summary>        /// <remarks>        /// <see cref="SaveOnClose"/> will be effective only if records have been loaded in memory either manually         /// by calling the <see cref="Load()"/> method or automatically by settings <see cref="LoadOnOpen"/> to true.        /// </remarks>        public bool SaveOnClose        {            get            {                return m_saveOnClose;            }            set            {                m_saveOnClose = value;            }        }         /// <summary>        /// Gets or sets a boolean value that indicates whether records loaded in memory are to be re-loaded when the         /// file is modified on disk.        /// </summary>        /// <remarks>        /// <see cref="ReloadOnModify"/> will be effective only if records have been loaded in memory either manually         /// by calling the <see cref="Load()"/> method or automatically by settings <see cref="LoadOnOpen"/> to true.        /// </remarks>        public bool ReloadOnModify        {            get            {                return m_reloadOnModify;            }

Lines 1–500 of 1405.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t