1279 lines · 51.8 KB · C#
RawDownload
//******************************************************************************************************//  StatisticsEngine.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://  ----------------------------------------------------------------------------------------------------//  02/22/2012 - Stephen C. Wills//       Generated original version of source code.//  12/20/2012 - Starlynn Danyelle Gilliam//       Modified Header.////****************************************************************************************************** using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Linq;using System.Reflection;using System.Text;using System.Text.RegularExpressions;using System.Timers;using GSF.Collections;using GSF.Configuration;using GSF.Data;using GSF.Diagnostics;using GSF.IO;using GSF.Parsing;using GSF.Threading;using GSF.TimeSeries.Adapters;using Timer = System.Timers.Timer; #pragma warning disable 414 // ReSharper disable NotAccessedField.Local// ReSharper disable UnusedMember.Local// ReSharper disable MemberHidesStaticFromOuterClassnamespace GSF.TimeSeries.Statistics{    /// <summary>    /// Represents the engine that computes statistics within applications of the TimeSeriesFramework.    /// </summary>    [Description("Statistics: defines the engine that computes all statistics within the system.")]    public class StatisticsEngine : FacileActionAdapterBase    {        #region [ Members ]         // Nested Types         // Represents a source for a statistics        private class StatisticSource        {            public WeakReference<object> SourceReference;            public string SourceName;            public string SourceCategory;            public string SourceAcronym;            public string StatisticMeasurementNameFormat;             public List<DataRow> StatisticMeasurements;            public bool HasUpdatedStatisticMeasurements;        }         // Represents a signal reference        private struct SignalReference        {            public readonly string Acronym;            public readonly int Index;            public readonly bool IsStatistic;             public SignalReference(string signal)            {                const string Pattern = "^(?<Acronym>.+)-ST(?<Index>[0-9]+)$";                Match match = Regex.Match(signal, Pattern);                 if (match.Success)                {                    Acronym = match.Groups["Acronym"].Value;                    Index = Convert.ToInt32(match.Groups["Index"].Value);                    IsStatistic = true;                }                else                {                    Acronym = signal;                    Index = 0;                    IsStatistic = false;                }            }        }         private class DBUpdateHelper        {            #region [ Members ]             // Fields            private readonly AdoDataConnection m_database;            private StatisticSource m_source;            private DataRow m_statistic;             private string m_name;            private int? m_historianID;            private object m_deviceID;            private string m_pointTag;            private int? m_signalTypeID;            private string m_signalReference;            private string m_description;             private Guid? m_nodeID;            private string m_nodeOwner;            private string m_company;             private Dictionary<string, DataRow> m_deviceLookup;            private Dictionary<int, string> m_companyLookup;             #endregion             #region [ Constructors ]             public DBUpdateHelper(AdoDataConnection database)            {                m_database = database;            }             #endregion             #region [ Properties ]             public StatisticSource Source            {                get                {                    return m_source;                }                set                {                    m_source = value;                    m_name = null;                    m_deviceID = null;                    m_company = null;                }            }             public DataRow Statistic            {                get                {                    return m_statistic;                }                set                {                    m_statistic = value;                    m_name = null;                    m_pointTag = null;                    m_signalReference = null;                    m_description = null;                }            }             public string Name => m_name ?? (m_name = GetName());             public int HistorianID => m_historianID ?? (int)(m_historianID = GetHistorianID());             public object DeviceID => m_deviceID ?? (m_deviceID = GetDeviceID());             public string PointTag => m_pointTag ?? (m_pointTag = GetPointTag());             public int SignalTypeID => m_signalTypeID ?? (int)(m_signalTypeID = GetSignalTypeID());             public string SignalReference => m_signalReference ?? (m_signalReference = GetSignalReference());             public string Description => m_description ?? (m_description = GetDescription());             public int Index => Convert.ToInt32(m_statistic["SignalIndex"]);             private Guid NodeID => m_nodeID ?? (Guid)(m_nodeID = GetNodeID());             private string Company => m_company ?? (m_company = GetCompany());             private string NodeOwner => m_nodeOwner ?? (m_nodeOwner = GetNodeOwner());             private string Category => m_source.SourceCategory;             private string Acronym => m_source.SourceAcronym;             private Dictionary<string, DataRow> DeviceLookup => m_deviceLookup ?? (m_deviceLookup = GetDeviceLookup());             private Dictionary<int, string> CompanyLookup => m_companyLookup ?? (m_companyLookup = GetCompanyLookup());             #endregion             #region [ Methods ]             private string GetName()            {                string arguments;                Dictionary<string, string> substitutions;                TemplatedExpressionParser parser;                 arguments = m_statistic.Field<string>("Arguments");                 if (string.IsNullOrWhiteSpace(arguments))                    return m_source.SourceName;                 substitutions = arguments.ParseKeyValuePairs();                parser = new TemplatedExpressionParser();                parser.TemplatedExpression = m_source.StatisticMeasurementNameFormat;                 if (substitutions.Count == 0)                {                    substitutions = arguments                        .Split(',')                        .Select((arg, index) => Tuple.Create(index.ToString(), arg))                        .ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2);                }                 substitutions = substitutions.ToDictionary(kvp => string.Concat("{", kvp.Key, "}"), kvp => kvp.Value);                substitutions["{}"] = m_source.SourceName;                 return parser.Execute(substitutions);            }             private int GetHistorianID()            {                const string StatHistorianIDFormat = "SELECT ID FROM Historian WHERE Acronym = 'STAT' AND NodeID = {0}";                return ExecuteScalar<int>(StatHistorianIDFormat, m_database.Guid(NodeID));            }             private object GetDeviceID()            {                DataRow device;                 if (!DeviceLookup.TryGetValue(Name, out device))                    return DBNull.Value;                 return device["ID"];            }             private string GetPointTag()            {                return $"{Company}_{Name}!{Acronym}:ST{Index}";            }             private int GetSignalTypeID()            {                const string SignalTypeIDFormat = "SELECT ID FROM SignalType WHERE Acronym = 'STAT'";                return ExecuteScalar<int>(SignalTypeIDFormat);            }             private string GetSignalReference()            {                return $"{Name}!{Acronym}-ST{Index}";            }             private string GetDescription()            {                return $"{Category} statistic for {m_statistic["Description"].ToNonNullString()}";            }             private Guid GetNodeID()            {                return Guid.Parse(ConfigurationFile.Current.Settings["systemSettings"]["NodeID"].Value);            }             private string GetCompany()            {                DataRow device;                int companyID;                string company = null;                 bool isNodeOwner = !DeviceLookup.TryGetValue(Name, out device) ||                                   !int.TryParse(device["CompanyID"].ToNonNullString(), out companyID) ||                                   !CompanyLookup.TryGetValue(companyID, out company);                 return isNodeOwner ? NodeOwner : company;            }             private string GetNodeOwner()            {                const string NodeCompanyIDFormat = "SELECT CompanyID FROM Node WHERE ID = {0}";                const string CompanyAcronymFormat = "SELECT MapAcronym FROM Company WHERE ID = {0}";                 int nodeCompanyID;                string companyAcronym;                 try                {                    nodeCompanyID = ExecuteScalar<int>(NodeCompanyIDFormat, m_database.Guid(NodeID));                    companyAcronym = ExecuteScalar<string>(CompanyAcronymFormat, nodeCompanyID);                }                catch                {                    companyAcronym = ConfigurationFile.Current.Settings["systemSettings"]["CompanyAcronym"].Value.TruncateRight(3);                }                 return companyAcronym;            }             private Dictionary<string, DataRow> GetDeviceLookup()            {                const string DeviceLookupFormat = "SELECT ID, Acronym, CompanyID FROM Device WHERE NodeID = {0}";                 return RetrieveData(DeviceLookupFormat, m_database.Guid(NodeID)).Select()                    .ToDictionary(row => row["Acronym"].ToNonNullString());            }             private Dictionary<int, string> GetCompanyLookup()            {                const string CompanyLookupFormat = "SELECT ID, Acronym FROM Company";                int id = 0;                 return RetrieveData(CompanyLookupFormat).Select()                    .Where(row => int.TryParse(row["ID"].ToNonNullString(), out id))                    .ToDictionary(row => id, row => row["Acronym"].ToNonNullString());            }             public T ExecuteScalar<T>(string queryFormat, params object[] parameters)            {                string query = m_database.ParameterizedQueryString(queryFormat, parameters.Select((parameter, index) => "p" + index).ToArray());                return (T)Convert.ChangeType(m_database.Connection.ExecuteScalar(query, DataExtensions.DefaultTimeoutDuration, parameters), typeof(T));            }             public void ExecuteNonQuery(string queryFormat, params object[] parameters)            {                string query = m_database.ParameterizedQueryString(queryFormat, parameters.Select((parameter, index) => "p" + index).ToArray());                m_database.Connection.ExecuteNonQuery(query, DataExtensions.DefaultTimeoutDuration, parameters);            }             public DataTable RetrieveData(string queryFormat, params object[] parameters)            {                string query = m_database.ParameterizedQueryString(queryFormat, parameters.Select((parameter, index) => "p" + index).ToArray());                return m_database.Connection.RetrieveData(m_database.AdapterType, query, DataExtensions.DefaultTimeoutDuration, parameters);            }             #endregion        }         // Events         /// <summary>        /// Event is raised before statistics calculation.        /// </summary>        public static event EventHandler BeforeCalculate;         /// <summary>        /// Event is raised after statistics calculation.        /// </summary>        public static event EventHandler Calculated;          // Fields        private readonly object m_statisticsLock;        private readonly List<Statistic> m_statistics;         private Timer m_reloadStatisticsTimer;        private Timer m_statisticCalculationTimer;         private readonly LongSynchronizedOperation m_updateStatisticMeasurementsOperation;        private readonly LongSynchronizedOperation m_loadStatisticsOperation;        private readonly LongSynchronizedOperation m_calculateStatisticsOperation;        private readonly ShortSynchronizedOperation m_validateSourceReferencesOperation;         private readonly PerformanceMonitor m_performanceMonitor;         private double m_reportingInterval;         private int m_lastStatisticCalculationCount;        private DateTime m_lastStatisticCalculationTime;         private bool m_disposed;         #endregion         #region [ Constructors ]         /// <summary>        /// Creates a new instance of the <see cref="StatisticsEngine"/> class.        /// </summary>        public StatisticsEngine()        {            m_statisticsLock = new object();            m_statistics = new List<Statistic>();            m_reloadStatisticsTimer = new Timer();            m_statisticCalculationTimer = new Timer();             // Set up the statistic calculation timer            m_reloadStatisticsTimer.Elapsed += ReloadStatisticsTimer_Elapsed;            m_reloadStatisticsTimer.Interval = 1.0D;            m_reloadStatisticsTimer.AutoReset = false;            m_reloadStatisticsTimer.Enabled = false;             m_updateStatisticMeasurementsOperation = new LongSynchronizedOperation(UpdateStatisticMeasurements, ex =>            {                string message = "An error occurred while attempting to update statistic measurement definitions: " + ex.Message;                OnProcessException(MessageLevel.Info, new InvalidOperationException(message, ex));            });             m_loadStatisticsOperation = new LongSynchronizedOperation(LoadStatistics, ex =>            {                string message = "An error occurred while attempting to load statistic definitions: " + ex.Message;                OnProcessException(MessageLevel.Info, new InvalidOperationException(message, ex));            });             m_calculateStatisticsOperation = new LongSynchronizedOperation(CalculateStatistics, ex =>            {                string message = "An error occurred while attempting to calculate statistics: " + ex.Message;                OnProcessException(MessageLevel.Info, new InvalidOperationException(message, ex));            });             m_validateSourceReferencesOperation = new ShortSynchronizedOperation(ValidateSourceReferences, ex =>            {                string message = "An error occurred while attempting to validate statistic source references: " + ex.Message;                OnProcessException(MessageLevel.Info, new InvalidOperationException(message, ex));            });             m_updateStatisticMeasurementsOperation.IsBackground = true;            m_loadStatisticsOperation.IsBackground = true;            m_calculateStatisticsOperation.IsBackground = true;             m_performanceMonitor = new PerformanceMonitor();             SourceRegistered += HandleSourceRegistered;        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets or sets <see cref="DataSet"/> based data source available to the <see cref="StatisticsEngine"/>.        /// </summary>        public override DataSet DataSource        {            get            {                return base.DataSource;            }            set            {                base.DataSource = value;                RestartReloadStatisticsTimer();            }        }         /// <summary>        /// Gets the flag indicating if this adapter supports temporal processing.        /// </summary>        public override bool SupportsTemporalProcessing => false;         /// <summary>        /// Returns the detailed status of the statistics engine.        /// </summary>        public override string Status        {            get            {                StringBuilder status = new StringBuilder(base.Status);                 status.AppendFormat("          Statistics count: {0}", m_statistics.Count);                status.AppendLine();                status.AppendFormat(" Recently calculated stats: {0}", m_lastStatisticCalculationCount);                status.AppendLine();                status.AppendFormat("     Last stat calculation: {0}", m_lastStatisticCalculationTime);                status.AppendLine();                 lock (StatisticSources)                {                    status.AppendFormat("    Statistic source count: {0}", StatisticSources.Count);                    status.AppendLine();                }                 return status.ToString();            }        }         #endregion         #region [ Methods ]         /// <summary>        /// Initializes <see cref="StatisticsEngine"/>.        /// </summary>        public override void Initialize()        {            Dictionary<string, string> settings;            string setting;             base.Initialize();            settings = Settings; 

Lines 1–500 of 1279.

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