Example #1
0
        /// <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();
                        }

                        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);
                    }
                }
            }
        }
Example #2
0
        /// <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();
        }
Example #3
0
        static void Main(string[] args)
        {
            string line;

            Console.WriteLine("Type HELP for a list of options.");
            Console.WriteLine();

            using (OutageLog log = new OutageLog())
            {
                log.FileName     = @"C:\Users\swills\test.txt";
                log.LogModified += (sender, arg) => Console.WriteLine("Modified!");
                log.Initialize();

                while (!(line = Console.ReadLine()).Equals("EXIT", StringComparison.OrdinalIgnoreCase))
                {
                    switch (line.ToUpper())
                    {
                    case "ADD":
                        log.Add(DateTimeOffset.UtcNow.AddSeconds(-1.0D), DateTimeOffset.UtcNow);
                        Console.WriteLine($"Count: {log.Count}");
                        break;

                    case "REMOVE":
                        log.Remove(log.First());
                        Console.WriteLine($"Count: {log.Count}");
                        break;

                    case "DUMP":
                        foreach (Outage outage in log.Outages)
                        {
                            Console.WriteLine($"{outage.Start:yyyy-MM-dd HH:mm:ss.fff};{outage.End:yyyy-MM-dd HH:mm:ss.fff}");
                        }

                        Console.WriteLine();
                        break;

                    case "STATUS":
                        Console.WriteLine(log.Status);
                        Console.WriteLine();
                        break;

                    case "HELP":
                        Console.WriteLine("ADD    - Adds a new outage to the log");
                        Console.WriteLine("REMOVE - Removes the first outage from the log");
                        Console.WriteLine("DUMP   - Displays the contents of the log");
                        Console.WriteLine("STATUS - Displays detailed status of the log");
                        Console.WriteLine("EXIT   - Exits this application");
                        Console.WriteLine();
                        break;
                    }
                }
            }
        }
Example #4
0
        /// <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();
            }

            if (settings.TryGetValue("startRecoveryBuffer", out setting) && double.TryParse(setting, out timeInterval))
            {
                StartRecoveryBuffer = timeInterval;
            }

            if (settings.TryGetValue("endRecoveryBuffer", out setting) && double.TryParse(setting, out timeInterval))
            {
                EndRecoveryBuffer = timeInterval;
            }

            // 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(MessageLevel.Warning, $"Logging path \"{setting}\" not found, defaulting to \"{FilePath.GetAbsolutePath("")}\"...", "Initialization");
                }
            }

            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};BypassStatistics=true";
            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, ex => OnProcessException(MessageLevel.Warning, ex), GSF.Common.Max(5000, (int)(m_recoveryStartDelay * 1000.0D)));
        }
Example #5
0
        /// <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)));
        }
Example #6
0
        /// <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);
                }
            }
        }
Example #7
0
        /// <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();
            }

            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          = 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)));
        }