Ejemplo n.º 1
0
 /// <summary>
 /// Signals the manager when a logical
 /// thread has new actions to be processed.
 /// </summary>
 /// <param name="thread">The thread with new actions to be processed.</param>
 internal void SignalItemHandler(LogicalThread thread)
 {
     if (thread.TryActivate())
     {
         m_logicalThreads.Enqueue(thread);
         ActivatePhysicalThread();
     }
 }
Ejemplo n.º 2
0
 /// <summary>
 /// Signals the manager when a logical
 /// thread has new actions to be processed.
 /// </summary>
 /// <param name="thread">The thread with new actions to be processed.</param>
 /// <param name="priority">The priority at which the thread is being signaled.</param>
 internal void SignalItemHandler(LogicalThread thread, int priority)
 {
     if (thread.TryActivate(priority))
     {
         Enqueue(thread);
         ActivatePhysicalThread();
     }
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Creates a new instance of the <see cref="LogicalThreadOperation"/> class.
        /// </summary>
        /// <param name="thread">The thread on which to execute the operation's action.</param>
        /// <param name="action">The action to be executed.</param>
        /// <param name="priority">The priority with which the action should be executed on the logical thread.</param>
        /// <param name="autoRunIfPending">
        /// Set to <c>true</c> to execute <see cref="RunIfPending"/> automatically; otherwise,
        /// set to <c>false</c> for user controlled call timing.
        /// </param>
        /// <exception cref="ArgumentException"><paramref name="priority"/> is outside the range between 1 and <see cref="LogicalThread.PriorityLevels"/>.</exception>
        public LogicalThreadOperation(LogicalThread thread, Action action, int priority, bool autoRunIfPending = true)
        {
            m_thread           = thread;
            m_action           = action;
            Priority           = priority;
            m_autoRunIfPending = autoRunIfPending;

            // Initialize this class with a cancelled token so that
            // calls to EnsurePriority before the first call to
            // ExecuteActionAsync do not inadvertently queue actions
            m_cancellationToken = new CancellationToken();
            m_cancellationToken.Cancel();
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Signals the manager when a logical
        /// thread has new actions to be processed.
        /// </summary>
        /// <param name="thread">The thread with new actions to be processed.</param>
        /// <param name="priority">The priority at which the thread is being signaled.</param>
        internal void SignalItemHandler(LogicalThread thread, int priority)
        {
            if (thread.TryActivate(priority))
            {
                // Make sure the thread has an action to be processed because
                // another thread could have processed all remaining actions and
                // deactivated the thread right before the call to TryActivate()
                if (!thread.HasAction)
                {
                    thread.Deactivate();
                    return;
                }

                Enqueue(thread);
                ActivatePhysicalThread();
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Queues the given thread for execution.
        /// </summary>
        /// <param name="thread">The thread to be queued for execution.</param>
        private void Enqueue(LogicalThread thread)
        {
            ICancellationToken executionToken;
            int activePriority;
            int nextPriority;

            do
            {
                // Create the execution token to be used in the closure
                ICancellationToken nextExecutionToken = new CancellationToken();

                // Always update the thread's active priority before
                // the execution token to mitigate race conditions
                nextPriority              = thread.NextPriority;
                thread.ActivePriority     = nextPriority;
                thread.NextExecutionToken = nextExecutionToken;

                // Now that the action can be cancelled by another thread using the
                // new cancellation token, it should be safe to put it in the queue
                m_logicalThreadQueues[PriorityLevels - nextPriority].Enqueue(() =>
                {
                    if (nextExecutionToken.Cancel())
                    {
                        return(thread);
                    }

                    return(null);
                });

                // Because enqueuing the thread is a multi-step process, we need to
                // double-check in case the thread's priority changed in the meantime
                activePriority = thread.ActivePriority;
                nextPriority   = thread.NextPriority;

                // We can use the cancellation token we just created because we only
                // really need to double-check the work that was done on this thread;
                // in other words, if another thread changed the priority in the
                // meantime, it can double-check its own work
                executionToken = nextExecutionToken;
            }while (activePriority != nextPriority && executionToken.Cancel());
        }
Ejemplo n.º 6
0
                /// <summary>
                /// Posts the <paramref name="continuation"/> back to the current context.
                /// </summary>
                /// <param name="continuation">The action to invoke asynchronously.</param>
                /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null.</exception>
                public void OnCompleted(Action continuation)
                {
                    if (continuation is null)
                    {
                        throw new ArgumentNullException(nameof(continuation));
                    }

                    LogicalThread thread = Awaitable.Thread
                                           ?? new LogicalThread();

                    int priority = Awaitable.Priority;

                    if (priority > 0)
                    {
                        thread.Push(priority, continuation);
                    }
                    else
                    {
                        thread.Push(continuation);
                    }
                }
Ejemplo n.º 7
0
 /// <summary>
 /// Creates an awaitable that ensures the continuation is running on the logical thread.
 /// </summary>
 /// <param name="thread">The thread to join.</param>
 /// <param name="priority">The priority of the continuation when completing asynchronously.</param>
 /// <returns>A context that, when awaited, runs on the logical thread.</returns>
 public static LogicalThreadAwaitable Join(this LogicalThread thread, int priority) =>
 new LogicalThreadAwaitable(thread, priority);
Ejemplo n.º 8
0
 /// <summary>
 /// Creates an awaitable that ensures the continuation is running on the logical thread.
 /// </summary>
 /// <param name="thread">The thread to join.</param>
 /// <returns>A context that, when awaited, runs on the logical thread.</returns>
 public static LogicalThreadAwaitable Join(this LogicalThread thread) =>
 new LogicalThreadAwaitable(thread);
        // Gets the thread used to process data for
        // the meter identified by the given asset key.
        private LogicalThread GetThread(string meterKey)
        {
            if ((object)meterKey == null)
                return m_noMeterThread ?? (m_noMeterThread = m_meterDataScheduler.CreateThread());

            return m_meterDataThreadLookup.GetOrAdd(meterKey, key =>
            {
                LogicalThread newThread = m_meterDataScheduler.CreateThread();

                newThread.UnhandledException += (sender, args) =>
                {
                    Exception ex = args.Argument;

                    if (ex is FileSkippedException)
                    {
                        Log.Warn(ex.Message);
                        return;
                    }

                    string message = $"Exception occurred processing data from meter \"{meterKey}\": {ex.Message}";
                    OnProcessException(new Exception(message, ex));
                };

                return newThread;
            });
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ServiceHelper"/> class.
        /// </summary>
        public ServiceHelper()
        {
            m_telnetSessionPassword = "******";
            m_logStatusUpdates = DefaultLogStatusUpdates;
            m_maxStatusUpdatesLength = DefaultMaxStatusUpdatesLength;
            m_maxStatusUpdatesFrequency = DefaultMaxStatusUpdatesFrequency;
            m_monitorServiceHealth = DefaultMonitorServiceHealth;
            m_healthMonitorInterval = DefaultHealthMonitorInterval;
            m_requestHistoryLimit = DefaultRequestHistoryLimit;
            m_supportFileManagementCommands = DefaultSupportFileManagementCommands;
            m_supportTelnetSessions = DefaultSupportTelnetSessions;
            m_supportSystemCommands = DefaultSupportSystemCommands;
            m_secureRemoteInteractions = DefaultSecureRemoteInteractions;
            m_serializationFormat = DefaultSerializationFormat;
            m_persistSettings = DefaultPersistSettings;
            m_settingsCategory = DefaultSettingsCategory;
            m_processes = new List<ServiceProcess>();
            m_remoteClients = new List<ClientInfo>();
            m_clientRequestHistory = new List<ClientRequestInfo>();
            m_serviceComponents = new List<object>();
            m_clientRequestHandlers = new List<ClientRequestHandler>();
            m_componentEnabledStates = new Dictionary<ISupportLifecycle, bool>();

            m_clientStatusUpdateLookup = new Dictionary<Guid, ClientStatusUpdateConfiguration>();
            m_threadScheduler = new LogicalThreadScheduler();
            m_threadScheduler.UnhandledException += LogicalThread_ProcessException;
            m_statusUpdateThread = m_threadScheduler.CreateThread(2);
            m_statusUpdateQueue = new List<StatusUpdate>();

            // Components
            m_statusLog = new LogFile();
            m_statusLog.FileName = "StatusLog.txt";
            m_statusLog.SettingsCategory = "StatusLog";
            m_statusLog.LogException += StatusLog_LogException;

            m_processScheduler = new ScheduleManager();
            m_processScheduler.SettingsCategory = "ProcessScheduler";
            m_processScheduler.ScheduleDue += Scheduler_ScheduleDue;

            m_errorLogger = new ErrorLogger();
            m_errorLogger.ExitOnUnhandledException = false;
            m_errorLogger.SettingsCategory = "ErrorLogger";
            m_errorLogger.ErrorLog.SettingsCategory = "ErrorLog";
            m_errorLogger.LoggingException += ErrorLogger_LoggingException;
        }
Ejemplo n.º 11
0
 /// <summary>
 /// Creates a new instance of the <see cref="LogicalThreadOperation"/> class.
 /// </summary>
 /// <param name="thread">The thread on which to execute the operation's action.</param>
 /// <param name="action">The action to be executed.</param>
 /// <param name="autoRunIfPending">
 /// Set to <c>true</c> to execute <see cref="RunIfPending"/> automatically; otherwise,
 /// set to <c>false</c> for user controlled call timing.
 /// </param>
 public LogicalThreadOperation(LogicalThread thread, Action action, bool autoRunIfPending = true)
     : this(thread, action, 1, autoRunIfPending)
 {
 }
Ejemplo n.º 12
0
        /// <summary>
        /// Creates a new instance of the <see cref="LogicalThreadOperation"/> class.
        /// </summary>
        /// <param name="thread">The thread on which to execute the operation's action.</param>
        /// <param name="action">The action to be executed.</param>
        /// <param name="priority">The priority with which the action should be executed on the logical thread.</param>
        /// <param name="autoRunIfPending">
        /// Set to <c>true</c> to execute <see cref="RunIfPending"/> automatically; otherwise, 
        /// set to <c>false</c> for user controlled call timing.
        /// </param>
        /// <exception cref="ArgumentException"><paramref name="priority"/> is outside the range between 1 and <see cref="LogicalThread.PriorityLevels"/>.</exception>
        public LogicalThreadOperation(LogicalThread thread, Action action, int priority, bool autoRunIfPending = true)
        {
            m_thread = thread;
            m_action = action;
            Priority = priority;
            m_autoRunIfPending = autoRunIfPending;

            // Initialize this class with a cancelled token so that
            // calls to EnsurePriority before the first call to
            // ExecuteActionAsync do not inadvertently queue actions
            m_cancellationToken = new CancellationToken();
            m_cancellationToken.Cancel();
        }
Ejemplo n.º 13
0
 /// <summary>
 /// Creates a new instance of the <see cref="LogicalThreadOperation"/> class.
 /// </summary>
 /// <param name="thread">The thread on which to execute the operation's action.</param>
 /// <param name="action">The action to be executed.</param>
 /// <param name="autoRunIfPending">
 /// Set to <c>true</c> to execute <see cref="RunIfPending"/> automatically; otherwise,
 /// set to <c>false</c> for user controlled call timing.
 /// </param>
 public LogicalThreadOperation(LogicalThread thread, Action action, bool autoRunIfPending = true)
     : this(thread, action, 1, autoRunIfPending)
 {
 }
Ejemplo n.º 14
0
        /// <summary>
        /// Creates a new instance of the <see cref="FileProcessor"/> class.
        /// </summary>
        /// <param name="processorID">Identifies the file processor so that it can locate its processed file cache.</param>
        public FileProcessor(Guid processorID)
        {
            m_processorID = processorID;

            m_filter = DefaultFilter;
            m_filterMethod = filePath => true;
            m_trackChanges = DefaultTrackChanges;
            m_cachePath = DefaultCachePath;
            m_internalBufferSize = DefaultInternalBufferSize;
            m_maxFragmentation = DefaultMaxFragmentation;
            m_enumerationStrategy = DefaultEnumerationStrategy;

            m_fileWatchersLock = new object();
            m_fileWatchers = new List<SafeFileWatcher>();
            m_threadScheduler = new LogicalThreadScheduler();
            m_threadScheduler.UnhandledException += (sender, args) => OnError(args.Argument);
            m_processingThread = m_threadScheduler.CreateThread(2);
            m_watcherThread = m_threadScheduler.CreateThread();
            m_fileWatchTimer = new Timer(15000);
            m_fileWatchTimer.Elapsed += FileWatchTimer_Elapsed;
            m_waitObject = new ManualResetEvent(false);

            m_touchedFiles = new Dictionary<string, DateTime>(StringComparer.OrdinalIgnoreCase);
            m_processedFiles = new FileBackedHashSet<string>(Path.Combine(m_cachePath, m_processorID.ToString()), StringComparer.OrdinalIgnoreCase);

            // Create the enumerator last since we are passing
            // a reference to 'this' into its constructor
            m_enumerator = new FileEnumerator(this);
        }
Ejemplo n.º 15
0
            /// <summary>
            /// Creates a new instance of the <see cref="FileEnumerator"/> class.
            /// </summary>
            /// <param name="fileProcessor">The file processor that created the file enumerator.</param>
            public FileEnumerator(FileProcessor fileProcessor)
            {
                m_fileProcessor = fileProcessor;
                m_cancellationTokens = new Dictionary<string, CancellationToken>();

                m_sequentialEnumerationThread = m_fileProcessor.m_threadScheduler.CreateThread();
                m_isActive = new LogicalThreadLocal<bool>();
                m_wrapperStack = new LogicalThreadLocal<Stack<Action>>(() => new Stack<Action>());
                m_directoryQueue = new LogicalThreadLocal<Queue<Action>>(() => new Queue<Action>());

                m_cleanProcessedFilesThread = m_fileProcessor.m_threadScheduler.CreateThread();
                m_cleanProcessedFilesOperation = new LogicalThreadOperation(m_cleanProcessedFilesThread, GetProcessedFiles, false);
            }
Ejemplo n.º 16
0
 /// <summary>
 /// Creates an awaitable that asynchronously yields
 /// to a new action on the logical thread when awaited.
 /// </summary>
 /// <param name="thread">The thread to yield to.</param>
 /// <returns>A context that, when awaited, will transition to a new action on the logical thread.</returns>
 public static LogicalThreadAwaitable Yield(this LogicalThread thread) =>
 new LogicalThreadAwaitable(thread, forceYield: true);
Ejemplo n.º 17
0
 /// <summary>
 /// Creates an awaitable that asynchronously yields
 /// to a new action on the logical thread when awaited.
 /// </summary>
 /// <param name="thread">The thread to yield to.</param>
 /// <param name="priority">The priority of the continuation.</param>
 /// <returns>A context that, when awaited, will transition to a new action on the logical thread.</returns>
 public static LogicalThreadAwaitable Yield(this LogicalThread thread, int priority) =>
 new LogicalThreadAwaitable(thread, priority, true);
Ejemplo n.º 18
0
 /// <summary>
 /// Signals the manager when a logical
 /// thread has new actions to be processed.
 /// </summary>
 /// <param name="thread">The thread with new actions to be processed.</param>
 internal void SignalItemHandler(LogicalThread thread)
 {
     if (thread.TryActivate())
     {
         m_logicalThreads.Enqueue(thread);
         ActivatePhysicalThread();
     }
 }
Ejemplo n.º 19
0
 /// <summary>
 /// Creates a new instance of the <see cref="LogicalThreadAwaitable"/> class.
 /// </summary>
 /// <param name="thread">The thread on which to push continuations.</param>
 /// <param name="priority">The priority of continuations pushed to the thread.</param>
 /// <param name="forceYield">Force continuations to complete asynchronously.</param>
 public LogicalThreadAwaitable(LogicalThread thread, int priority = 0, bool forceYield = false)
 {
     Thread     = thread;
     Priority   = priority;
     ForceYield = forceYield;
 }
Ejemplo n.º 20
0
 public ClientStatusUpdateConfiguration(Guid clientID, ServiceHelper serviceHelper)
 {
     m_clientID = clientID;
     m_filter = new ClientFilter();
     m_thread = serviceHelper.m_threadScheduler.CreateThread(2);
     m_messageCounts = new List<Tuple<DateTime, int>>();
     m_serviceHelper = serviceHelper;
 }