/// <summary> /// Initializes the <see cref="DataGapRecoverer"/>. /// </summary> public void Initialize() { if (m_disposed) throw new InvalidOperationException("Data gap recoverer has been disposed. Cannot initialize."); Dictionary<string, string> settings = m_connectionString.ToNonNullString().ParseKeyValuePairs(); string setting; double timeInterval; int processingInterval; if (settings.TryGetValue("sourceConnectionName", out setting) && !string.IsNullOrWhiteSpace(setting)) m_sourceConnectionName = setting; if (settings.TryGetValue("recoveryStartDelay", out setting) && double.TryParse(setting, out timeInterval)) RecoveryStartDelay = timeInterval; if (settings.TryGetValue("dataMonitoringInterval", out setting) && double.TryParse(setting, out timeInterval)) DataMonitoringInterval = timeInterval; if (settings.TryGetValue("minimumRecoverySpan", out setting) && double.TryParse(setting, out timeInterval)) MinimumRecoverySpan = timeInterval; if (settings.TryGetValue("maximumRecoverySpan", out setting) && double.TryParse(setting, out timeInterval)) MaximumRecoverySpan = timeInterval; if (settings.TryGetValue("filterExpression", out setting) && !string.IsNullOrWhiteSpace(setting)) FilterExpression = setting; if (settings.TryGetValue("recoveryProcessingInterval", out setting) && int.TryParse(setting, out processingInterval)) RecoveryProcessingInterval = processingInterval; if (settings.TryGetValue("useMillisecondResolution", out setting)) UseMillisecondResolution = setting.ParseBoolean(); // Get logging path, if any has been defined if (settings.TryGetValue("loggingPath", out setting)) { setting = FilePath.GetDirectoryName(FilePath.GetAbsolutePath(setting)); if (Directory.Exists(setting)) m_loggingPath = setting; else OnStatusMessage("WARNING: Logging path \"{0}\" not found, defaulting to \"{1}\"...", setting, FilePath.GetAbsolutePath("")); } if (string.IsNullOrEmpty(m_sourceConnectionName)) throw new NullReferenceException("Source connection name must defined - it is used to create outage log file name."); // Setup a new temporal data subscriber that will be used to query historical data m_temporalSubscription = new DataSubscriber(); m_temporalSubscription.Name = m_sourceConnectionName + "!" + GetType().Name; m_temporalSubscription.DataSource = m_dataSource; m_temporalSubscription.ConnectionString = m_connectionString; m_temporalSubscription.StatusMessage += Common_StatusMessage; m_temporalSubscription.ProcessException += Common_ProcessException; m_temporalSubscription.ConnectionEstablished += TemporalSubscription_ConnectionEstablished; m_temporalSubscription.ConnectionTerminated += TemporalSubscription_ConnectionTerminated; m_temporalSubscription.ProcessingComplete += TemporalSubscription_ProcessingComplete; m_temporalSubscription.NewMeasurements += TemporalSubscription_NewMeasurements; m_temporalSubscription.Initialize(); // Setup data gap outage log to persist unprocessed outages between class life-cycles m_dataGapLog = new OutageLog(); m_dataGapLog.FileName = GetLoggingPath(m_sourceConnectionName + "_OutageLog.txt"); m_dataGapLog.ProcessException += Common_ProcessException; m_dataGapLog.Initialize(); // Setup data gap processor to process items one at a time, a 5-second minimum period is established between each gap processing m_dataGapLogProcessor = new OutageLogProcessor(m_dataGapLog, ProcessDataGap, CanProcessDataGap, OnProcessException, GSF.Common.Max(5000, (int)(m_recoveryStartDelay * SI.Milli))); }
/// <summary> /// Releases the unmanaged resources used by the <see cref="DataGapRecoverer"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected virtual void Dispose(bool disposing) { if (!m_disposed) { try { if (disposing) { if ((object)m_dataGapRecoveryCompleted != null) { // Signal any waiting threads m_abnormalTermination = true; m_dataGapRecoveryCompleted.Set(); m_dataGapRecoveryCompleted.Dispose(); m_dataGapRecoveryCompleted = null; } if ((object)m_dataStreamMonitor != null) { m_dataStreamMonitor.Elapsed -= DataStreamMonitor_Elapsed; m_dataStreamMonitor.Dispose(); m_dataStreamMonitor = null; } if ((object)m_dataGapLogProcessor != null) { m_dataGapLogProcessor.Dispose(); m_dataGapLogProcessor = null; } if ((object)m_dataGapLog != null) { m_dataGapLog.ProcessException -= Common_ProcessException; m_dataGapLog.Dispose(); m_dataGapLog = null; } if ((object)m_temporalSubscription != null) { m_temporalSubscription.StatusMessage -= Common_StatusMessage; m_temporalSubscription.ProcessException -= Common_ProcessException; m_temporalSubscription.ConnectionEstablished -= TemporalSubscription_ConnectionEstablished; m_temporalSubscription.ConnectionTerminated -= TemporalSubscription_ConnectionTerminated; m_temporalSubscription.NewMeasurements -= TemporalSubscription_NewMeasurements; m_temporalSubscription.ProcessingComplete -= TemporalSubscription_ProcessingComplete; m_temporalSubscription.Dispose(); m_temporalSubscription = null; } } } finally { m_disposed = true; // Prevent duplicate dispose. if ((object)Disposed != null) Disposed(this, EventArgs.Empty); } } }