/// <summary> /// Creates a <see cref="OutageLogProcessor"/> using a pre-initialized <see cref="OutageLog"/>. /// </summary> /// <param name="outageLog">Pre-initialized <see cref="OutageLog"/> to process.</param> /// <param name="processOutageFunction">A delegate that defines a processing function for an <see cref="Outage"/>.</param> /// <param name="canProcessOutageFunction">A delegate that determines if an <see cref="Outage"/> can currently be processed.</param> /// <param name="processExceptionHandler">Delegate to handle any exceptions encountered while processing as <see cref="Outage"/>.</param> /// <param name="processingInterval">Processing interval, in milliseconds.</param> public OutageLogProcessor(OutageLog outageLog, Action<Outage> processOutageFunction, Func<Outage, bool> canProcessOutageFunction, Action<Exception> processExceptionHandler, int processingInterval) { if ((object)outageLog == null) throw new ArgumentNullException("outageLog"); if ((object)processOutageFunction == null) throw new ArgumentNullException("processOutageFunction"); if ((object)canProcessOutageFunction == null) throw new ArgumentNullException("canProcessOutageFunction"); if ((object)processExceptionHandler == null) throw new ArgumentNullException("processExceptionHandler"); m_outageLog = outageLog; m_outageLog.CollectionChanged += outageLog_CollectionChanged; m_processOutageFunction = processOutageFunction; m_canProcessOutageFunction = canProcessOutageFunction; m_processInterval = processingInterval; m_enabled = true; m_operation = new LongSynchronizedOperation(ProcessNextItem, processExceptionHandler); m_operation.IsBackground = true; m_operation.RunOnceAsync(); }
//private Dictionary<MeasurementKey, double> m_baseVoltages; #endregion /// <summary> /// Creates a new instance of the EPRI <see cref="FileExporter"/>. /// </summary> public FileExporter() { m_fileExport = new LongSynchronizedOperation(WriteFileData, OnProcessException) { IsBackground = true }; m_fileDataLock = new object(); }
/// <summary> /// Constructs a new instance of the <see cref="InputAdapterBase"/>. /// </summary> protected InputAdapterBase() { m_connectionOperation = new LongSynchronizedOperation(AttemptConnectionOperation) { IsBackground = true }; m_connectionTimer = Common.TimerScheduler.CreateTimer(2000); m_connectionTimer.Elapsed += m_connectionTimer_Elapsed; m_connectionTimer.AutoReset = false; m_connectionTimer.Enabled = false; }
/// <summary> /// Creates a new instance of the <see cref="ReportingProcessBase"/> class. /// </summary> /// <param name="reportType">Report type - passed into StatHistorianReportGenerator.</param> protected ReportingProcessBase(string reportType) { m_reportType = reportType; m_reportGenerationQueue = new ConcurrentQueue<Tuple<DateTime, bool>>(); m_executeOperation = new LongSynchronizedOperation(Execute) { IsBackground = true }; m_persistSettings = true; m_settingsCategory = string.Format("{0}Reporting", m_reportType); m_archiveFilePath = "Eval(statArchiveFile.FileName)"; m_reportLocation = "Reports"; m_title = string.Format("Eval(securityProvider.ApplicationName) {0} Report", m_reportType); m_company = "Eval(systemSettings.CompanyName)"; m_idleReportLifetime = 14.0D; m_enableReportEmail = false; m_smtpServer = "localhost"; m_fromAddress = "*****@*****.**"; m_toAddresses = "*****@*****.**"; }
/// <summary> /// Event handler for service starting operations. /// </summary> /// <param name="sender">Event source.</param> /// <param name="e">Event arguments containing command line arguments passed into service at startup.</param> /// <remarks> /// Time-series framework uses this handler to load settings from configuration file as service is starting. /// </remarks> protected virtual void ServiceStartingHandler(object sender, EventArgs<string[]> e) { ShutdownHandler.Initialize(); // Define a run-time log m_runTimeLog = new RunTimeLog(); m_runTimeLog.FileName = "RunTimeLog.txt"; m_runTimeLog.ProcessException += ProcessExceptionHandler; m_runTimeLog.Initialize(); // Initialize Iaon session m_iaonSession = new IaonSession(); m_iaonSession.StatusMessage += StatusMessageHandler; m_iaonSession.ProcessException += ProcessExceptionHandler; m_iaonSession.ConfigurationChanged += ConfigurationChangedHandler; // Create a handler for unobserved task exceptions TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; // Make sure default service settings exist ConfigurationFile configFile = ConfigurationFile.Current; string servicePath = FilePath.GetAbsolutePath(""); string cachePath = string.Format("{0}{1}ConfigurationCache{1}", servicePath, Path.DirectorySeparatorChar); string defaultLogPath = string.Format("{0}{1}Logs{1}", servicePath, Path.DirectorySeparatorChar); // System settings CategorizedSettingsElementCollection systemSettings = configFile.Settings["systemSettings"]; systemSettings.Add("ConfigurationType", "Database", "Specifies type of configuration: Database, WebService, BinaryFile or XmlFile"); systemSettings.Add("ConnectionString", "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=IaonHost.mdb", "Configuration database connection string"); systemSettings.Add("DataProviderString", "AssemblyName={System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089};ConnectionType=System.Data.OleDb.OleDbConnection;AdapterType=System.Data.OleDb.OleDbDataAdapter", "Configuration database ADO.NET data provider assembly type creation string"); systemSettings.Add("ConfigurationCachePath", cachePath, "Defines the path used to cache serialized configurations"); systemSettings.Add("LogPath", defaultLogPath, "Defines the path used to archive log files"); systemSettings.Add("MaxLogFiles", DefaultMaxLogFiles, "Defines the maximum number of log files to keep"); systemSettings.Add("CachedConfigurationFile", "SystemConfiguration.xml", "File name for last known good system configuration (only cached for a Database or WebService connection)"); systemSettings.Add("UniqueAdaptersIDs", "True", "Set to true if all runtime adapter ID's will be unique to allow for easier adapter specification"); systemSettings.Add("ProcessPriority", "High", "Sets desired process priority: Normal, AboveNormal, High, RealTime"); systemSettings.Add("AllowRemoteRestart", "True", "Controls ability to remotely restart the host service."); systemSettings.Add("MinThreadPoolWorkerThreads", DefaultMinThreadPoolSize, "Defines the minimum number of allowed thread pool worker threads."); systemSettings.Add("MaxThreadPoolWorkerThreads", DefaultMaxThreadPoolSize, "Defines the maximum number of allowed thread pool worker threads."); systemSettings.Add("MinThreadPoolIOPortThreads", DefaultMinThreadPoolSize, "Defines the minimum number of allowed thread pool I/O completion port threads (used by socket layer)."); systemSettings.Add("MaxThreadPoolIOPortThreads", DefaultMaxThreadPoolSize, "Defines the maximum number of allowed thread pool I/O completion port threads (used by socket layer)."); systemSettings.Add("ConfigurationBackups", DefaultConfigurationBackups, "Defines the total number of older backup configurations to maintain."); systemSettings.Add("PreferCachedConfiguration", "False", "Set to true to try the cached configuration first, before loading database configuration - typically used when cache is updated by external process."); systemSettings.Add("LocalCertificate", $"{ServiceName}.cer", "Path to the local certificate used by this server for authentication."); systemSettings.Add("RemoteCertificatesPath", @"Certs\Remotes", "Path to the directory where remote certificates are stored."); systemSettings.Add("DefaultCulture", "en-US", "Default culture to use for language, country/region and calendar formats."); // Example connection settings CategorizedSettingsElementCollection exampleSettings = configFile.Settings["exampleConnectionSettings"]; exampleSettings.Add("SqlServer.ConnectionString", "Data Source=serverName; Initial Catalog=databaseName; User ID=userName; Password=password", "Example SQL Server database connection string"); exampleSettings.Add("SqlServer.DataProviderString", "AssemblyName={System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}; ConnectionType=System.Data.SqlClient.SqlConnection; AdapterType=System.Data.SqlClient.SqlDataAdapter", "Example SQL Server database .NET provider string"); exampleSettings.Add("MySQL.ConnectionString", "Server=serverName;Database=databaseName; Uid=root; Pwd=password; allow user variables = true;", "Example MySQL database connection string"); exampleSettings.Add("MySQL.DataProviderString", "AssemblyName={MySql.Data, Version=6.3.6.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d}; ConnectionType=MySql.Data.MySqlClient.MySqlConnection; AdapterType=MySql.Data.MySqlClient.MySqlDataAdapter", "Example MySQL database .NET provider string"); exampleSettings.Add("Oracle.ConnectionString", "Data Source=tnsName; User ID=schemaUserName; Password=schemaPassword", "Example Oracle database connection string"); exampleSettings.Add("Oracle.DataProviderString", "AssemblyName={Oracle.DataAccess, Version=2.112.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342}; ConnectionType=Oracle.DataAccess.Client.OracleConnection; AdapterType=Oracle.DataAccess.Client.OracleDataAdapter", "Example Oracle database .NET provider string"); exampleSettings.Add("SQLite.ConnectionString", "Data Source=databaseName.db; Version=3; Foreign Keys=True; FailIfMissing=True", "Example SQLite database connection string"); exampleSettings.Add("SQLite.DataProviderString", "AssemblyName={System.Data.SQLite, Version=1.0.99.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139}; ConnectionType=System.Data.SQLite.SQLiteConnection; AdapterType=System.Data.SQLite.SQLiteDataAdapter", "Example SQLite database .NET provider string"); exampleSettings.Add("OleDB.ConnectionString", "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=databaseName.mdb", "Example Microsoft Access (via OleDb) database connection string"); exampleSettings.Add("OleDB.DataProviderString", "AssemblyName={System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}; ConnectionType=System.Data.OleDb.OleDbConnection; AdapterType=System.Data.OleDb.OleDbDataAdapter", "Example OleDb database .NET provider string"); exampleSettings.Add("Odbc.ConnectionString", "Driver={SQL Server Native Client 10.0}; Server=serverName; Database=databaseName; Uid=userName; Pwd=password;", "Example ODBC database connection string"); exampleSettings.Add("Odbc.DataProviderString", "AssemblyName={System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}; ConnectionType=System.Data.Odbc.OdbcConnection; AdapterType=System.Data.Odbc.OdbcDataAdapter", "Example ODBC database .NET provider string"); exampleSettings.Add("WebService.ConnectionString", "http://localhost/ConfigSource/SystemConfiguration.xml", "Example web service connection string"); exampleSettings.Add("XmlFile.ConnectionString", "SystemConfiguration.xml", "Example XML configuration file connection string"); // Attempt to set default culture try { string defaultCulture = systemSettings["DefaultCulture"].ValueAs("en-US"); CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture(defaultCulture); // Defaults for date formatting, etc. CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture(defaultCulture); // Culture for resource strings, etc. } catch (Exception ex) { DisplayStatusMessage("Failed to set default culture due to exception, defaulting to \"{1}\": {0}", UpdateType.Alarm, ex.Message, CultureInfo.CurrentCulture.Name.ToNonNullNorEmptyString("Undetermined")); LogException(ex); } // Retrieve application log path as defined in the config file string logPath = FilePath.GetAbsolutePath(systemSettings["LogPath"].Value); // Make sure log directory exists try { if (!Directory.Exists(logPath)) Directory.CreateDirectory(logPath); } catch (Exception ex) { // Attempt to default back to common log file path if (!Directory.Exists(defaultLogPath)) { try { Directory.CreateDirectory(defaultLogPath); } catch { defaultLogPath = servicePath; } } DisplayStatusMessage("Failed to create logging directory \"{0}\" due to exception, defaulting to \"{1}\": {2}", UpdateType.Alarm, logPath, defaultLogPath, ex.Message); LogException(ex); logPath = defaultLogPath; } int maxLogFiles = systemSettings["MaxLogFiles"].ValueAs(DefaultMaxLogFiles); try { Logger.FileWriter.SetPath(logPath); Logger.FileWriter.SetLoggingFileCount(maxLogFiles); } catch (Exception ex) { DisplayStatusMessage("Failed to set logging path \"{0}\" or max file count \"{1}\" due to exception: {2}", UpdateType.Alarm, logPath, maxLogFiles, ex.Message); LogException(ex); } // Retrieve configuration cache directory as defined in the config file cachePath = FilePath.GetAbsolutePath(systemSettings["ConfigurationCachePath"].Value); // Make sure configuration cache directory exists try { if (!Directory.Exists(cachePath)) Directory.CreateDirectory(cachePath); } catch (Exception ex) { DisplayStatusMessage("Failed to create configuration cache directory \"{0}\" due to exception: {1}", UpdateType.Alarm, cachePath, ex.Message); LogException(ex); } try { Directory.SetCurrentDirectory(servicePath); } catch (Exception ex) { DisplayStatusMessage("Failed to set current directory to execution path \"{0}\" due to exception: {1}", UpdateType.Alarm, servicePath, ex.Message); LogException(ex); } // Initialize system settings m_configurationType = systemSettings["ConfigurationType"].ValueAs<ConfigurationType>(); m_cachedXmlConfigurationFile = FilePath.AddPathSuffix(cachePath) + systemSettings["CachedConfigurationFile"].Value; m_cachedBinaryConfigurationFile = FilePath.AddPathSuffix(cachePath) + FilePath.GetFileNameWithoutExtension(m_cachedXmlConfigurationFile) + ".bin"; m_configurationBackups = systemSettings["ConfigurationBackups"].ValueAs(DefaultConfigurationBackups); m_uniqueAdapterIDs = systemSettings["UniqueAdaptersIDs"].ValueAsBoolean(true); m_allowRemoteRestart = systemSettings["AllowRemoteRestart"].ValueAsBoolean(true); m_preferCachedConfiguration = systemSettings["PreferCachedConfiguration"].ValueAsBoolean(false); m_reloadConfigQueue = ProcessQueue<Tuple<string, Action<bool>>>.CreateSynchronousQueue(ExecuteReloadConfig, 500.0D, Timeout.Infinite, false, false); m_reloadConfigQueue.ProcessException += m_iaonSession.ProcessExceptionHandler; m_configurationCacheOperation = new LongSynchronizedOperation(ExecuteConfigurationCache) { IsBackground = true }; // Setup default thread pool size try { ThreadPool.SetMinThreads(systemSettings["MinThreadPoolWorkerThreads"].ValueAs(DefaultMinThreadPoolSize), systemSettings["MinThreadPoolIOPortThreads"].ValueAs(DefaultMinThreadPoolSize)); ThreadPool.SetMaxThreads(systemSettings["MaxThreadPoolWorkerThreads"].ValueAs(DefaultMaxThreadPoolSize), systemSettings["MaxThreadPoolIOPortThreads"].ValueAs(DefaultMaxThreadPoolSize)); } catch (Exception ex) { DisplayStatusMessage("Failed to set desired thread pool size due to exception: {0}", UpdateType.Alarm, ex.Message); LogException(ex); } // Define guid with query string delimiters according to database needs if (string.IsNullOrWhiteSpace(m_nodeIDQueryString)) m_nodeIDQueryString = "'" + m_iaonSession.NodeID + "'"; // Set up the configuration loader switch (m_configurationType) { case ConfigurationType.Database: m_configurationLoader = new DatabaseConfigurationLoader { ConnectionString = systemSettings["ConnectionString"].Value, DataProviderString = systemSettings["DataProviderString"].Value, NodeIDQueryString = m_nodeIDQueryString }; break; case ConfigurationType.WebService: m_configurationLoader = new WebServiceConfigurationLoader { URI = systemSettings["ConnectionString"].Value }; break; case ConfigurationType.BinaryFile: m_configurationLoader = new BinaryFileConfigurationLoader { FilePath = systemSettings["ConnectionString"].Value }; break; case ConfigurationType.XmlFile: m_configurationLoader = new XMLConfigurationLoader { FilePath = systemSettings["ConnectionString"].Value }; break; } m_binaryCacheConfigurationLoader = new BinaryFileConfigurationLoader { FilePath = m_cachedBinaryConfigurationFile }; m_xmlCacheConfigurationLoader = new XMLConfigurationLoader { FilePath = m_cachedXmlConfigurationFile }; m_configurationLoader.StatusMessage += (o, args) => DisplayStatusMessage(args.Argument, UpdateType.Information); m_binaryCacheConfigurationLoader.StatusMessage += (o, args) => DisplayStatusMessage(args.Argument, UpdateType.Information); m_xmlCacheConfigurationLoader.StatusMessage += (o, args) => DisplayStatusMessage(args.Argument, UpdateType.Information); m_configurationLoader.ProcessException += ConfigurationLoader_ProcessException; m_binaryCacheConfigurationLoader.ProcessException += ConfigurationLoader_ProcessException; m_xmlCacheConfigurationLoader.ProcessException += ConfigurationLoader_ProcessException; m_reloadConfigQueue.Start(); #if !MONO try { // Attempt to assign desired process priority. Note that process will require SeIncreaseBasePriorityPrivilege or // Administrative privileges to make this change Process.GetCurrentProcess().PriorityClass = systemSettings["ProcessPriority"].ValueAs<ProcessPriorityClass>(); } catch (Exception ex) { LogException(ex); } #endif }
/// <summary> /// Creates a new instance of the <see cref="AlarmAdapter"/> class. /// </summary> public AlarmAdapter() { m_alarmLock = new object(); m_alarmLookup = new Dictionary<Guid, SignalAlarms>(); m_measurementQueue = new DoubleBufferedQueue<IMeasurement>(); m_processMeasurementsOperation = new MixedSynchronizedOperation(ProcessMeasurements, OnProcessException); m_alarmLogOperation = new LongSynchronizedOperation(LogStateChanges, OnProcessException); m_stateChanges = new DoubleBufferedQueue<StateChange>(); m_alarmLogOperation.IsBackground = true; }
/// <summary> /// Constructs a new instance of the <see cref="OutputAdapterBase"/>. /// </summary> protected OutputAdapterBase() { m_metadataRefreshOperation = new LongSynchronizedOperation(ExecuteMetadataRefresh) { IsBackground = true }; m_measurementQueue = ProcessQueue<IMeasurement>.CreateRealTimeQueue(ProcessMeasurements); m_measurementQueue.ProcessException += m_measurementQueue_ProcessException; m_connectionOperation = new LongSynchronizedOperation(AttemptConnectionOperation) { IsBackground = true }; m_connectionTimer = Common.TimerScheduler.CreateTimer(2000); m_connectionTimer.Elapsed += m_connectionTimer_Elapsed; m_connectionTimer.AutoReset = false; m_connectionTimer.Enabled = false; // We monitor total number of unarchived measurements every 5 seconds - this is a useful statistic to monitor, if // total number of unarchived measurements gets very large, measurement archival could be falling behind m_monitorTimer = Common.TimerScheduler.CreateTimer(5000); m_monitorTimer.Elapsed += m_monitorTimer_Elapsed; m_monitorTimer.AutoReset = true; m_monitorTimer.Enabled = false; }
/// <summary> /// Creates a new instance of the <see cref="SandBoxEngine"/> class. /// </summary> public SandBoxEngine() { m_processLatestDataOperation = new LongSynchronizedOperation(ProcessLatestDataOperation, ex => Log.Error(ex.Message, ex)); }
/// <summary> /// Creates a new <see cref="DataSubscriber"/>. /// </summary> public DataSubscriber() { m_registerStatisticsOperation = new LongSynchronizedOperation(HandleDeviceStatisticsRegistration) { IsBackground = true }; m_requests = new List<ServerCommand>(); m_synchronizeMetadataOperation = new LongSynchronizedOperation(SynchronizeMetadata) { IsBackground = true }; m_encoding = Encoding.Unicode; m_operationalModes = DefaultOperationalModes; m_metadataSynchronizationTimeout = DefaultMetadataSynchronizationTimeout; m_allowedParsingExceptions = DefaultAllowedParsingExceptions; m_parsingExceptionWindow = DefaultParsingExceptionWindow; string loggingPath = FilePath.GetDirectoryName(FilePath.GetAbsolutePath(DefaultLoggingPath)); if (Directory.Exists(loggingPath)) m_loggingPath = loggingPath; // Default to not using transactions for meta-data on SQL server (helps avoid deadlocks) try { using (AdoDataConnection database = new AdoDataConnection("systemSettings")) { m_useTransactionForMetadata = database.DatabaseType != DatabaseType.SQLServer; } } catch { m_useTransactionForMetadata = DefaultUseTransactionForMetadata; } DataLossInterval = 10.0D; m_bufferBlockCache = new List<BufferBlockMeasurement>(); m_useLocalClockAsRealTime = true; }
/// <summary> /// Initializes a new instance of the <see cref="ConfigurationFile"/> class. /// </summary> internal ConfigurationFile(string configFilePath) { m_culture = CultureInfo.InvariantCulture; // Do not run the save operation on a background thread since the application may be // performing the save as a final step during shutdown and the save operation must // complete, incomplete saves can cause a zero length config file to be created. m_saveOperation = new LongSynchronizedOperation(ExecuteConfigurationSave) { IsBackground = false }; m_configuration = GetConfiguration(configFilePath); if (m_configuration.HasFile && File.Exists(m_configuration.FilePath)) ValidateConfigurationFile(m_configuration.FilePath); else CreateConfigurationFile(m_configuration.FilePath); m_configuration = GetConfiguration(configFilePath); m_userConfiguration = new UserConfigurationFile(); }
/// <summary> /// Creates a new <see cref="SubscriberStatusQuery"/>. /// </summary> public SubscriberStatusQuery() { m_serviceClient = CommonFunctions.GetWindowsServiceClient(); m_serviceClient.Helper.ReceivedServiceResponse += Helper_ReceivedServiceResponse; m_subscriberStatuses = new List<Tuple<Guid, bool, string>>(); m_responseComplete = new AutoResetEvent(false); m_statusQueryOperation = new LongSynchronizedOperation(ExecuteStatusQuery) { IsBackground = true }; m_statusQueryIDs = new HashSet<Guid>(); m_statusQueryLock = new object(); m_responseTimeout = DefaultResponseTimeout; m_statusQueryOperation.IsBackground = true; }
/// <summary> /// Initializes a new instance of the <see cref="MultipleDestinationExporter"/> class. /// </summary> /// <param name="settingsCategory">The config file settings category under which the export destinations are defined.</param> /// <param name="exportTimeout">The total allowed time in milliseconds for each export to execute.</param> public MultipleDestinationExporter(string settingsCategory, int exportTimeout) { m_exportTimeout = exportTimeout; m_settingsCategory = settingsCategory; m_persistSettings = DefaultPersistSettings; m_maximumRetryAttempts = DefaultMaximumRetryAttempts; m_retryDelayInterval = DefaultRetryDelayInterval; m_textEncoding = Encoding.Default; // We use default ANSI page encoding for text based exports... m_exportDestinationsLock = new object(); m_exportOperation = new LongSynchronizedOperation(ExecuteExports, OnProcessException) { IsBackground = true }; }
/// <summary> /// Creates a new instance of the <see cref="RoutingTables"/> class. /// </summary> public RoutingTables(IRouteMappingTables mappingTable = null) { m_prevCalculatedConsumers = new HashSet<IAdapter>(); m_prevCalculatedProducers = new HashSet<IAdapter>(); m_routeMappingTables = mappingTable ?? new RouteMappingDoubleBufferQueue(); m_routeMappingTables.Initialize(OnStatusMessage, OnProcessException); m_calculateRoutingTablesOperation = new LongSynchronizedOperation(CalculateRoutingTables) { IsBackground = true }; }
/// <summary> /// Creates a new instance of the <see cref="InterprocessCache"/> with the specified number of <paramref name="maximumConcurrentLocks"/>. /// </summary> /// <param name="maximumConcurrentLocks">Maximum concurrent reader locks to allow.</param> public InterprocessCache(int maximumConcurrentLocks) { // Initialize field values m_loadOperation = new LongSynchronizedOperation(SynchronizedRead) { IsBackground = true }; m_saveOperation = new LongSynchronizedOperation(SynchronizedWrite); m_loadIsReady = new ManualResetEventSlim(false); m_saveIsReady = new ManualResetEventSlim(true); m_maximumConcurrentLocks = maximumConcurrentLocks; m_maximumRetryAttempts = DefaultMaximumRetryAttempts; m_retryQueue = new BitArray(2); m_fileData = new byte[0]; // Setup retry timer m_retryTimer = new Timer(); m_retryTimer.Elapsed += m_retryTimer_Elapsed; m_retryTimer.AutoReset = false; m_retryTimer.Interval = DefaultRetryDelayInterval; }
/// <summary> /// Initializes <see cref="TimeSeriesProducer"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary<string, string> settings = Settings; string setting; int value; // Parse required settings if (!settings.TryGetValue(nameof(Servers), out setting) || string.IsNullOrWhiteSpace(setting)) throw new ArgumentException($"Required \"{nameof(Servers)}\" setting is missing."); Servers = setting.Trim(); m_servers = Servers.Split(',').Select(uri => new Uri(uri)).ToArray(); // Parse optional settings if (settings.TryGetValue(nameof(Topic), out setting) && !string.IsNullOrWhiteSpace(setting)) Topic = setting.Trim(); else Topic = DefaultTopic; if (settings.TryGetValue(nameof(Partitions), out setting) && int.TryParse(setting, out value)) Partitions = value; else Partitions = DefaultPartitions; if (settings.TryGetValue(nameof(Encoding), out setting)) Encoding = setting; else Encoding = null; if (settings.TryGetValue(nameof(TimestampFormat), out setting)) TimestampFormat = setting; else TimestampFormat = DefaultTimestampFormat; if (settings.TryGetValue(nameof(ValueFormat), out setting)) ValueFormat = setting; else ValueFormat = DefaultValueFormat; if (settings.TryGetValue(nameof(SerializeMetadata), out setting)) SerializeMetadata = setting.ParseBoolean(); else SerializeMetadata = DefaultSerializeMetadata; if (settings.TryGetValue(nameof(CacheMetadataLocally), out setting)) CacheMetadataLocally = setting.ParseBoolean(); else CacheMetadataLocally = DefaultCacheMetadataLocally; if (CacheMetadataLocally) m_cacheMetadataLocally = new LongSynchronizedOperation(() => TimeSeriesMetadata.CacheLocally(m_metadata, MetadataTopic, status => OnStatusMessage(MessageLevel.Info, status))) { IsBackground = true }; }
/// <summary> /// Initializes <see cref="TimeSeriesProducer"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary<string, string> settings = Settings; string setting; int intValue; double doubleValue; // Parse required settings if (!settings.TryGetValue(nameof(Servers), out setting) || string.IsNullOrWhiteSpace(setting)) throw new ArgumentException($"Required \"{nameof(Servers)}\" setting is missing."); Servers = setting.Trim(); m_servers = Servers.Split(',').Select(uri => new Uri(uri)).ToArray(); // Parse optional settings if (settings.TryGetValue(nameof(Topic), out setting) && !string.IsNullOrWhiteSpace(setting)) Topic = setting.Trim(); else Topic = TimeSeriesProducer.DefaultTopic; if (settings.TryGetValue(nameof(Partitions), out setting) && int.TryParse(setting, out intValue)) Partitions = intValue; else Partitions = TimeSeriesProducer.DefaultPartitions; if (settings.TryGetValue(nameof(TrackConsumerOffset), out setting)) TrackConsumerOffset = setting.ParseBoolean(); else TrackConsumerOffset = DefaultTrackConsumerIndex; if (!settings.TryGetValue(nameof(ConsumerOffsetFileName), out setting) || string.IsNullOrWhiteSpace(setting)) setting = Name + ".offset"; ConsumerOffsetFileName = FilePath.GetAbsolutePath(setting); if (settings.TryGetValue(nameof(ConsumerOffsetCacheInterval), out setting) && double.TryParse(setting, out doubleValue)) ConsumerOffsetCacheInterval = doubleValue; else ConsumerOffsetCacheInterval = DefaultConsumerOffsetCacheInterval; if (settings.TryGetValue(nameof(ReadDelay), out setting) && int.TryParse(setting, out intValue)) ReadDelay = intValue; else ReadDelay = DefaultReadDelay; if (settings.TryGetValue(nameof(CacheMetadataLocally), out setting)) CacheMetadataLocally = setting.ParseBoolean(); else CacheMetadataLocally = TimeSeriesProducer.DefaultCacheMetadataLocally; if (CacheMetadataLocally) m_cacheMetadataLocally = new LongSynchronizedOperation(() => TimeSeriesMetadata.CacheLocally(m_metadata, MetadataTopic, status => OnStatusMessage(MessageLevel.Info, status))) { IsBackground = true }; if ((object)OutputMeasurements != null && OutputMeasurements.Length > 0) m_outputMeasurementKeys = new HashSet<MeasurementKey>(OutputMeasurements.Select(m => m.Key)); }
/// <summary> /// Creates a new <see cref="AuthorizedMeasurementsQuery"/>. /// </summary> public AuthorizedMeasurementsQuery() { m_serviceClient = CommonFunctions.GetWindowsServiceClient(); m_serviceClient.Helper.ReceivedServiceResponse += Helper_ReceivedServiceResponse; m_authorizedSignalIDs = new List<Guid>(); m_responseComplete = new AutoResetEvent(false); m_authorizationQueryOperation = new LongSynchronizedOperation(ExecuteAuthorizationQuery) { IsBackground = true }; m_authorizationQueryIDs = new HashSet<Guid>(); m_authorizationQueryLock = new object(); m_responseTimeout = DefaultResponseTimeout; }
// Per partition consumer read handler private void ProcessPartitionMessages(object state) { int partition = (int)state; try { Dictionary<uint, MeasurementKey> idTable = new Dictionary<uint, MeasurementKey>(); ConsumerOptions options = new ConsumerOptions(Topic, m_router); LongSynchronizedOperation cacheLastConsumerOffset = null; OffsetPosition consumerCursor = new OffsetPosition { PartitionId = partition, Offset = 0 }; long lastUpdateTime = 0; long lastMetadataUpdateCount = 0; long lastMeasurementTime = 0; options.PartitionWhitelist.Add(partition); options.Log = new TimeSeriesLogger((message, parameters) => OnStatusMessage(MessageLevel.Info, string.Format($"P[{partition}]: " + message, parameters)), ex => OnProcessException(MessageLevel.Warning, ex)); // Handle consumer offset tracking, i.e., adapter will start reading messages where it left off from last run if (TrackConsumerOffset) { // Parse path/filename.ext into constituent parts string[] fileParts = new string[3]; fileParts[0] = FilePath.GetDirectoryName(ConsumerOffsetFileName); // 0: path/ fileParts[1] = FilePath.GetFileNameWithoutExtension(ConsumerOffsetFileName); // 1: filename fileParts[2] = FilePath.GetExtension(ConsumerOffsetFileName); // 2: .ext // Include partition index as part of consumer offset cache file name string fileName = $"{fileParts[0]}{fileParts[1]}-P{partition}{fileParts[2]}"; if (File.Exists(fileName)) { try { // Read last consumer offset consumerCursor.Offset = long.Parse(File.ReadAllText(fileName)); } catch (Exception ex) { OnProcessException(MessageLevel.Warning, new InvalidOperationException($"Failed to read last consumer offset from \"{fileName}\": {ex.Message}", ex)); } } cacheLastConsumerOffset = new LongSynchronizedOperation(() => { // Do not write file any more often than defined consumer offset cache interval int restTime = (int)(Ticks.FromSeconds(ConsumerOffsetCacheInterval) - (DateTime.UtcNow.Ticks - lastUpdateTime)).ToMilliseconds(); if (restTime > 0) Thread.Sleep(restTime); lastUpdateTime = DateTime.UtcNow.Ticks; // Write current consumer offset File.WriteAllText(fileName, consumerCursor.Offset.ToString()); }, ex => OnProcessException(MessageLevel.Warning, new InvalidOperationException($"Failed to cache current consumer offset to \"{fileName}\": {ex.Message}", ex))) { IsBackground = true }; } using (Consumer consumer = new Consumer(options, new OffsetPosition(partition, consumerCursor.Offset))) { lock (m_consumers) m_consumers.Add(new WeakReference<Consumer>(consumer)); foreach (Message message in consumer.Consume()) { if ((object)m_metadata == null) continue; uint id; byte metadataVersion; IMeasurement measurement = message.KafkaDeserialize(out id, out metadataVersion); // Kick-off a refresh for new metadata if message version numbers change if (m_lastMetadataVersion != metadataVersion) { m_lastMetadataVersion = metadataVersion; m_updateMetadata.RunOnceAsync(); } // Clear all undefined items in dictionary when metadata gets updated if (lastMetadataUpdateCount < m_metadataUpdateCount) { lastMetadataUpdateCount = m_metadataUpdateCount; foreach (uint undefinedID in idTable.Where(item => item.Value.SignalID == Guid.Empty).Select(item => item.Key).ToArray()) idTable.Remove(undefinedID); } // Get associated measurement key, or look it up in metadata table measurement.Metadata = idTable.GetOrAdd(id, lookupID => MeasurementKey.LookUpBySignalID(m_metadata?.Records?.FirstOrDefault(record => record.ID == lookupID)?.ParseSignalID() ?? Guid.Empty)).Metadata; // Only publish measurements with associated metadata and are assigned to this adapter if (measurement.Key != MeasurementKey.Undefined && ((object)m_outputMeasurementKeys == null || m_outputMeasurementKeys.Contains(measurement.Key))) OnNewMeasurements(new[] { measurement }); // Cache last consumer offset consumerCursor.Offset = message.Offset; if ((object)cacheLastConsumerOffset != null) cacheLastConsumerOffset.RunOnceAsync(); if (ReadDelay > -1) { // As a group of measurements transition from timestamp to another, inject configured read delay if (lastMeasurementTime != measurement.Timestamp) Thread.Sleep(ReadDelay); lastMeasurementTime = measurement.Timestamp; } } } } catch (Exception ex) { OnProcessException(MessageLevel.Warning, new InvalidOperationException($"Exception while reading Kafka messages for topic \"{Topic}\" P[{partition}]: {ex.Message}", ex)); } }
//private Dictionary<MeasurementKey, double> m_baseVoltages; #endregion /// <summary> /// Creates a new instance of the EPRI <see cref="FileExporter"/>. /// </summary> public FileExporter() { m_fileExport = new LongSynchronizedOperation(WriteFileData, ex => OnProcessException(MessageLevel.Error, ex)) { IsBackground = true }; m_fileDataLock = new object(); }
/// <summary> /// Creates a new <see cref="TimeSeriesConsumer"/> instance. /// </summary> public TimeSeriesConsumer() { m_consumers = new List<WeakReference<Consumer>>(); m_updateMetadata = new LongSynchronizedOperation(UpdateMetadata, ex => OnProcessException(MessageLevel.Warning, ex)) { IsBackground = true }; }
/// <summary> /// Creates a new <see cref="AlarmStatusQuery"/>. /// </summary> public AlarmStatusQuery() { // Attach to service connected events CommonFunctions.ServiceConnectionRefreshed += CommonFunctions_ServiceConnectionRefreshed; // Determine initial state of connectivity UpdateServiceConnectivity(); m_alarmStateQueryOperation = new LongSynchronizedOperation(ExecuteAlarmStateQuery) { IsBackground = true }; m_responseComplete = new AutoResetEvent(false); m_responseTimeout = DefaultResponseTimeout; }
/// <summary> /// Creates a new instance of the <see cref="RoutingTables"/> class. /// </summary> public RoutingTables() { m_calculateRoutingTablesOperation = new LongSynchronizedOperation(CalculateRoutingTables) { IsBackground = true }; }