//******************************************************************************************************// 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; namespace 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 { get { return m_name ?? (m_name = GetName()); } } public int HistorianID { get { return m_historianID ?? (int)(m_historianID = GetHistorianID()); } } public object DeviceID { get { return m_deviceID ?? (m_deviceID = GetDeviceID()); } } public string PointTag { get { return m_pointTag ?? (m_pointTag = GetPointTag()); } } public int SignalTypeID { get { return m_signalTypeID ?? (int)(m_signalTypeID = GetSignalTypeID()); } } public string SignalReference { get { return m_signalReference ?? (m_signalReference = GetSignalReference()); } } public string Description { get { return m_description ?? (m_description = GetDescription()); } } public int Index { get { return Convert.ToInt32(m_statistic["SignalIndex"]); } } private Guid NodeID { get { return m_nodeID ?? (Guid)(m_nodeID = GetNodeID()); } } private string Company { get { return m_company ?? (m_company = GetCompany()); } } private string NodeOwner { get { return m_nodeOwner ?? (m_nodeOwner = GetNodeOwner()); } } private string Category { get { return m_source.SourceCategory; } } private string Acronym { get { return m_source.SourceAcronym; } } private Dictionary<string, DataRow> DeviceLookup { get { return m_deviceLookup ?? (m_deviceLookup = GetDeviceLookup()); } } private Dictionary<int, string> CompanyLookup { get { return 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 string.Format("{0}_{1}!{2}:ST{3}", Company, Name, Acronym, Index); } private int GetSignalTypeID() { const string SignalTypeIDFormat = "SELECT ID FROM SignalType WHERE Acronym = 'STAT'"; return ExecuteScalar<int>(SignalTypeIDFormat); } private string GetSignalReference() { return string.Format("{0}!{1}-ST{2}", Name, Acronym, Index); } private string GetDescription() { return string.Format("{0} statistic for {1}", Category, 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(new InvalidOperationException(message, ex)); }); m_loadStatisticsOperation = new LongSynchronizedOperation(LoadStatistics, ex => { string message = "An error occurred while attempting to load statistic definitions: " + ex.Message; OnProcessException(new InvalidOperationException(message, ex)); }); m_calculateStatisticsOperation = new LongSynchronizedOperation(CalculateStatistics, ex => {Lines 1–500 of 1335. Load more
//****************************************************************************************************** // 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; namespace 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 { get { return m_name ?? (m_name = GetName()); } } public int HistorianID { get { return m_historianID ?? (int)(m_historianID = GetHistorianID()); } } public object DeviceID { get { return m_deviceID ?? (m_deviceID = GetDeviceID()); } } public string PointTag { get { return m_pointTag ?? (m_pointTag = GetPointTag()); } } public int SignalTypeID { get { return m_signalTypeID ?? (int)(m_signalTypeID = GetSignalTypeID()); } } public string SignalReference { get { return m_signalReference ?? (m_signalReference = GetSignalReference()); } } public string Description { get { return m_description ?? (m_description = GetDescription()); } } public int Index { get { return Convert.ToInt32(m_statistic["SignalIndex"]); } } private Guid NodeID { get { return m_nodeID ?? (Guid)(m_nodeID = GetNodeID()); } } private string Company { get { return m_company ?? (m_company = GetCompany()); } } private string NodeOwner { get { return m_nodeOwner ?? (m_nodeOwner = GetNodeOwner()); } } private string Category { get { return m_source.SourceCategory; } } private string Acronym { get { return m_source.SourceAcronym; } } private Dictionary<string, DataRow> DeviceLookup { get { return m_deviceLookup ?? (m_deviceLookup = GetDeviceLookup()); } } private Dictionary<int, string> CompanyLookup { get { return 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 string.Format("{0}_{1}!{2}:ST{3}", Company, Name, Acronym, Index); } private int GetSignalTypeID() { const string SignalTypeIDFormat = "SELECT ID FROM SignalType WHERE Acronym = 'STAT'"; return ExecuteScalar<int>(SignalTypeIDFormat); } private string GetSignalReference() { return string.Format("{0}!{1}-ST{2}", Name, Acronym, Index); } private string GetDescription() { return string.Format("{0} statistic for {1}", Category, 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(new InvalidOperationException(message, ex)); }); m_loadStatisticsOperation = new LongSynchronizedOperation(LoadStatistics, ex => { string message = "An error occurred while attempting to load statistic definitions: " + ex.Message; OnProcessException(new InvalidOperationException(message, ex)); }); m_calculateStatisticsOperation = new LongSynchronizedOperation(CalculateStatistics, ex => {