Friday, July 27, 2012

A Simple Framework for Windows Service 3 of 3

Source code for Service Framework posts.
In the previous post I covered the ThreadServiceBase class that serves as the foundation class for services whose main work is a loop that runs in a thread for the life of the service. This final post in the series covers two classes for services that are Timer based.

TimerServiceBase

This is the base class for services whose work is a relatively short duration method that is executed repeatedly by regular, periodic firings of a System.Timers.Timer event. This is much better than having a long running method with a loop and a Thread.Sleep() call within the loop. Using the timer allows the service to be much more responsive to requests from the service control manager to stop or pause.
Since it's possible that the work method might at times take longer to finish than the timer interval, you'll need to decide what the appropriate behavior is in that case. If that occurs, the timer will call the method again on a second thread. TimerServiceBase has an AllowOverlappingWork property to specify the behavior you want. If you set it to true, then your method will be called each time the timer fires, even if one or more previous executions of the method have not finished. Each execution of the work method will be on a separate thread. If you set AllowOverlappingWork to false, then TimerServiceBase will skip calling your work method if it is still running from the previous timer event. If your work method may execute for longer than a few seconds, you should make use of the passed in abortFlag and continueFlag to ensure your service is responsive to requests originating from the service control manager.
This following code shows a simple example of a service that descends from TimerServiceBase.

// Copyright ©2012 SoftWx, Inc.
// Released under the MIT License the text of which appears at the end of this file.
// <authors> Steve Hatchett

using System;
using System.Threading;
using SoftWx.ServiceProcess;

namespace ServiceTest {
partial class ExampleTimerService : TimerServiceBase {
public ExampleTimerService() {
InitializeComponent();
}

private void InitializeComponent() {
//
// ExampleTimerService
//
this.AllowOverlappingWork = true;
this.CanPauseAndContinue = true;
this.CanShutdown = true;
this.Interval = 2000;
this.ServiceName = "ExampleTimerService";

}

protected override void OnWork(SignalToken abortFlag, SignalToken continueFlag) {
DateTime now = DateTime.Now;
// show we've entered this invocation of OnWork
string timeMsg = "OnWork time=" + now.ToString("hh:mm:ss ffff");
WriteLogEntry(timeMsg, System.Diagnostics.EventLogEntryType.Information);

// simulate doing some work
Thread.Sleep(800);

// example of pause handling that stays within the method, rather than just exiting the method on pause
if (!continueFlag.IsSet) {
WaitHandle.WaitAny(new WaitHandle[] { continueFlag.WaitHandle, abortFlag.WaitHandle});
}
// show we're at he end of this invocation of OnWork
WriteLogEntry(" exiting " + timeMsg, System.Diagnostics.EventLogEntryType.Information);
}
}
}


In the code for TimerServiceBase, you can see how it handles the basic housekeeping of starting/stopping and pausing/continuing the service, and complete management of the underlying Timer.


// Copyright ©2012 SoftWx, Inc.
// Released under the MIT License the text of which appears at the end of this file.
// version 1.3 - 7/25/2012
// <authors> Steve Hatchett

using System;
using System.Diagnostics;
using System.Threading;

namespace SoftWx.ServiceProcess {
/// <summary>
/// Service base class that uses a Timer to execute work at periodic intervals.
/// </summary>
public class TimerServiceBase : ExecutableServiceBase {
private readonly SignalSource abortFlag = new SignalSource(); // flag used to signal worker method we need to stop
private readonly SignalSource continueFlag = new SignalSource(); // flag used to signal worker method we can continue (i.e. not paused)
private System.Timers.Timer timer = new System.Timers.Timer(); // service timer - calls work method in a pooled thread
private volatile bool allowOverlappingWork = false; // specifies whether work method will execute on timer fire when the method from previous fire still hasn't finished
private int workingCount = 0; // count of work methods currently exectuting (will be 0 or 1 if allowOverlappingWork is false, otherwise 0..n)

/// <summary> Create a new instance of TimerServiceBase.</summary>
public TimerServiceBase() {
this.abortFlag.Set(false);
this.continueFlag.Set(true);

// initialize the Timer
this.timer.Elapsed += TimerFired;
this.timer.AutoReset = true;
}

/// <summary>
/// Gets or sets the interval in milliseconds at which to call the OnWork method.
/// </summary>
public double Interval {
get { return this.timer.Interval; }
set { this.timer.Interval = value; }
}

/// <summary>
/// Gets or sets the value indicating whether the OnWork method will be executed when
/// the timer fires before the OnWork method from the previous timer event has completed.
/// </summary>
public bool AllowOverlappingWork {
get { return this.allowOverlappingWork; }
set { this.allowOverlappingWork = value; }
}

/// <summary>
/// Performs the service's work upon the firing of the timer event.
/// </summary>
/// <param name="abortFlag">Signals that the service must stop as soon as possible.</param>
/// <param name="continueFlag">Signals that the service can continue (i.e. it is not paused).</param>
protected virtual void OnWork(SignalToken abortFlag, SignalToken continueFlag) { }

/// <summary>Start the service.</summary>
protected override void OnStart(string[] args) {
this.timer.Start();
}

/// <summary>Stop the service.</summary>
protected override void OnStop() {
// indicate that we are stopping - this will signal
// any worker code currently executing, and also
// prevent our TimerFired from doing any work if
// it gets called any more
abortFlag.Set(true);
var ticks = Environment.TickCount;

// stop the Timer from firing - note that the Stop is queued
// up for execution on another thread. Because of that, it's
// possible that the timer could still fire after we call Stop,
// but if it does, work will be skipped because we've set the
// abortFlag above.
this.timer.Stop();

// wait for work in the TimerFired to finish
int seconds = 0;
bool cleanExit = true;
while (Interlocked.CompareExchange(ref this.workingCount, -1, 0) != 0) {
if (seconds >= 10) {
seconds = 0;
var elapsed = Environment.TickCount - ticks;
if (elapsed >= MaxWaitSeconds * 1000) {
cleanExit = false;
break;
}
if (IsRunningAsService) {
this.RequestAdditionalTime(elapsed + (15 * 1000));
}
WriteLogEntry("Requesting additional time to stop", EventLogEntryType.Information);
}
Thread.Sleep(1000); // normally like to avoid Sleep, but this only executes rarely, during service stopping
seconds++;
}
ticks = Environment.TickCount - ticks;
if (cleanExit) {
WriteLogEntry("Worker methods exited cleanly in " + ticks + " milliseconds", EventLogEntryType.Information);
} else {
WriteLogEntry("Worker methods did not exit cleanly within " + ticks + " milliseconds", EventLogEntryType.Information);
}
}

/// <summary>Pause the service.</summary>
protected override void OnPause() {
this.continueFlag.Set(false);
this.timer.Stop();
}

/// <summary>Continue the paused service.</summary>
protected override void OnContinue() {
this.continueFlag.Set(true);
this.timer.Start();
}

/// <summary>Releases all resources used by the TimerServiceBase.</summary>
protected override void Dispose(bool disposing) {
this.timer.Dispose();
}

/// <summary>Handles the timer event.</summary>
private void TimerFired(object sender, System.Timers.ElapsedEventArgs e) {
// When overlapping work execution is not allowed, ensure that only one
// execution of work is going on at one time. If work is still ongoing
// when the timer fires, processing is skipped.
bool allowOverlapping = this.allowOverlappingWork;
if (allowOverlapping || (Interlocked.CompareExchange(ref this.workingCount, 1, 0) == 0)) {
if (allowOverlapping) Interlocked.Increment(ref this.workingCount);
try {
// if we're not currently stopping, do the work
if (!abortFlag.IsSet) OnWork(this.abortFlag.Token, this.continueFlag.Token);
}
catch (OperationCanceledException) {
// quietly swallow OperationCancelledException as it's an acceptable response to abortFlag signalling need to abort.
}
finally {
Interlocked.Decrement(ref this.workingCount);
}
}
}
}
}



ScheduleServiceBase


This is the base class for services whose work is a relatively short duration method that is executed at a scheduled time. Like TimerServiceBase, it uses a System.Timers.Timer under the covers. Rather than call your work method at regular, periodic intervals, ScheduleServiceBase calls the work method at a scheduled DateTime. Upon exit, your work method returns the next DateTime that it wishes to be called again. On service start, the work method is called almost immediately after start to get things going. This class could be used for situations where you have a list of jobs, with each needing execution at different periodic intervals. Rather than create timers for each one, you can maintiain a list of the jobs, along with when they next need to run. When you enter the work method, you run through the list, executing all the jobs whose time has arrived. When you exit the work method, you return the time of the job with the soonest next execution time.


This following code shows a simple example of a service that descends from ScheduleServiceBase.


// Copyright ©2012 SoftWx, Inc.
// Released under the MIT License the text of which appears at the end of this file.
// <authors> Steve Hatchett

using System;
using System.Threading;
using SoftWx.ServiceProcess;

namespace ServiceTest {
partial class ExampleScheduleService : ScheduleServiceBase {
private Periodic[] periodics;

public ExampleScheduleService() {
InitializeComponent();
// set up three periodic events, each occurring at different periods
this.periodics = new Periodic[3];
this.periodics[0] = new Periodic(10, DateTime.Now);
this.periodics[1] = new Periodic(15, DateTime.Now);
this.periodics[2] = new Periodic(25, DateTime.Now);
}

private void InitializeComponent() {
//
// ExampleScheduleService
//
this.CanPauseAndContinue = true;
this.CanShutdown = true;
this.ServiceName = "ExampleScheduleService";

}

protected override DateTime OnWork(SignalToken abortFlag, SignalToken continueFlag) {
// show that scheduled work started
DateTime time = DateTime.Now;
WriteLogEntry("OnWork time=" + time.ToString("hh:mm:ss"),
System.Diagnostics.EventLogEntryType.Information);

// loop through all scheduled events, simulate processing the ones
// that are due (or will be due within a time so short that it's near the
// resolution of the system timer), and determine next scheduled time
DateTime next = DateTime.MaxValue;
foreach(var periodic in this.periodics) {
DateTime now = DateTime.Now;
if (periodic.Next <= now.AddMilliseconds(15)) {
WriteLogEntry(" processing " + periodic.IntervalSecs + " second periodic",
System.Diagnostics.EventLogEntryType.Information);

// set up next time for this event, ensuring next time is in the future.
// We need the future check because this could be the first call to
// OnWork after a long service Pause.
do {
periodic.Next = periodic.Next.AddSeconds(periodic.IntervalSecs);
} while (periodic.Next < now);
}
// next scheduled time for work is whichever next event time is the soonest
if (periodic.Next < next) next = periodic.Next;
}

WriteLogEntry(" next scheduled time=" + next.ToString("hh:mm:ss"), System.Diagnostics.EventLogEntryType.Information);
return next;
}

private class Periodic {
public int IntervalSecs;
public DateTime Next;
public Periodic(int interval, DateTime next) {
IntervalSecs = interval;
Next = next;
}
}
}
}


In the code for ScheduleServiceBase, you can see how it handles the basic housekeeping of starting/stopping and pausing/continuing the service, and complete management of the underlying Timer. One big difference from TimerServiceBase is that the timer runs with AutoReset set to false. So the whole issue of the timer event executing the work method multiple times cannot arise. As soon as the work method is called, the timer is off. When the work method exits, it returns the next scheduled time, and with that information, ScheduleServiceBase can set the new timer Interval, and start the timer again.


// Copyright ©2012 SoftWx, Inc.
// Released under the MIT License the text of which appears at the end of this file.
// version 1.3 - 7/25/2012
// <authors> Steve Hatchett

using System;
using System.Diagnostics;
using System.Threading;

namespace SoftWx.ServiceProcess {
/// <summary>
/// Service base class that uses a Timer to execute work at the next scheduled time.
/// </summary>
public class ScheduleServiceBase : ExecutableServiceBase {
private readonly SignalSource abortFlag = new SignalSource(); // flag used to signal worker method we need to stop
private readonly SignalSource continueFlag = new SignalSource(); // flag used to signal worker method we can continue (i.e. not paused)
private System.Timers.Timer timer = new System.Timers.Timer(); // service timer - calls work method in a pooled thread
private int workingCount = 0; // count of work methods currently exectuting (will be 0 or 1)
private DateTime nextFiring; // the desired DateTime of the next scheduled timer event

/// <summary>Create a new instance of ScheduleServiceBase.</summary>
public ScheduleServiceBase() {
this.abortFlag.Set(false);
this.continueFlag.Set(true);

// initialize the Timer
this.timer.Elapsed += TimerFired;
this.timer.AutoReset = false;
}

/// <summary>
/// Performs the service's work upon the firing of the timer event.
/// </summary>
/// <param name="abortFlag">Signals that the service must stop as soon as possible.</param>
/// <param name="continueFlag">Signals that the service can continue (i.e. it is not paused).</param>
protected virtual DateTime OnWork(SignalToken abortFlag, SignalToken continueFlag) {
return DateTime.Now.AddSeconds(1);
}

/// <summary>Start the service.</summary>
protected override void OnStart(string[] args) {
this.timer.Interval = 100;
this.timer.Start();
}

/// <summary>Stop the service.</summary>
protected override void OnStop() {
// indicate that we are stopping - this will signal
// any worker code currently executing, and also
// prevent our TimerFired from doing any work if
// it gets called any more
abortFlag.Set(true);
var ticks = Environment.TickCount;

// stop the Timer from firing - note that the Stop is queued
// up for execution on another thread. Because of that, it's
// possible that the timer could still fire after we call Stop,
// but if it does, work will be skipped because we've set the
// abortFlag above.
this.timer.Stop();

// wait for work in the TimerFired to finish
int seconds = 0;
bool cleanExit = true;
while (Interlocked.CompareExchange(ref this.workingCount, -1, 0) != 0) {
if (seconds >= 10) {
seconds = 0;
var elapsed = Environment.TickCount - ticks;
if (elapsed >= MaxWaitSeconds * 1000) {
cleanExit = false;
break;
}
if (IsRunningAsService) {
this.RequestAdditionalTime(elapsed + (15 * 1000));
}
WriteLogEntry("Requesting additional time to stop", EventLogEntryType.Information);
}
Thread.Sleep(1000); // normally like to avoid Sleep, but this only executes rarely, during service stopping
seconds++;
}
ticks = Environment.TickCount - ticks;
if (cleanExit) {
WriteLogEntry("Worker method exited cleanly in " + ticks + " milliseconds", EventLogEntryType.Information);
} else {
WriteLogEntry("Worker method did not exit cleanly within " + ticks + " milliseconds", EventLogEntryType.Information);
}
}

/// <summary>Pause the service.</summary>
protected override void OnPause() {
this.continueFlag.Set(false);
this.timer.Stop();
}

/// <summary>Continue the paused service.</summary>
protected override void OnContinue() {
if (Interlocked.CompareExchange(ref this.workingCount, 0, 0) == 0) {
// not paused in the middle of the OnWork method
this.continueFlag.Set(true);
SetInterval();
this.timer.Start();
} else {
// paused in the middle of the OnWork method
this.continueFlag.Set(true);
}
}

/// <summary>Releases all resources used by the ScheduleServiceBase.</summary>
protected override void Dispose(bool disposing) {
this.timer.Dispose();
}

private void TimerFired(object sender, System.Timers.ElapsedEventArgs e) {
// note that since timer has AutoReset=false, it should not be possible for this
// method to get called a second time before the previous invocation has finished.
// We still used the interloced workingCount though, so we can stop the service
// cleanly.
if (Interlocked.CompareExchange(ref this.workingCount, 1, 0) == 0) {
try {
// if we're not currently stopping, do the work
if (!abortFlag.IsSet) {
this.nextFiring = OnWork(this.abortFlag.Token, this.continueFlag.Token);
}
}
catch (OperationCanceledException) {
// quietly swallow OperationCancelledException as it's an acceptable response to abortFlag signalling need to abort.
} finally {
Interlocked.Decrement(ref this.workingCount);
}
}
SetInterval();
this.timer.Start();
}

private void SetInterval() {
double msecsToNextFire = (this.nextFiring - DateTime.Now).TotalMilliseconds;
if (msecsToNextFire <= 0) msecsToNextFire = 15;
this.timer.Interval = msecsToNextFire;
}
}
}

Wednesday, July 25, 2012

A Simple Framework for Windows Services 2 of 3

Source code for Service Framework posts.
In the previous post I covered the ExecutableServiceBase class that serves as the foundation class for a simple Windows Service framework. In this and the next post, I’ll cover classes that build on that to provide functionality that’s commonly desired in a Windows Service application.

ThreadServiceBase

This post covers ThreadServiceBase, which serves as the base class for services that run on their own thread from the time the service starts until it is stopped. Typically this type of service runs in a loop that only exits when signaled through the abortFlag that the service needs to stop. There will be a point in the loop where it blocks on something, like waiting for a message on a MessageQueue, or waiting for a socket connection, so it doesn't spin and burn CPU cycles. I’ll walk through this step by step assuming you’re starting with a new service project created with the Visual Studio Windows Service template. Most of the steps are common to all the different type of service base classes in this simple framework. In this walkthrough, we’ll be creating the ExampleThreadService.
  1. Add the SoftWx.ServiceProcess project to your service project’s solution.
  2. Add a reference to the SoftWx.ServiceProcess assembly in your service project.
  3. Edit your service project’s Application properties. Change Output Type from “Windows Application” to “Console Application”.
  4. Change the name of the service file from “Service1” to “ExampleThreadService”.
  5. Edit the Program.cs file. Add a “using” for SoftWx.ServiceProcess, and change the Main method as shown below.
using SoftWx.ServiceProcess;

namespace ServiceTest {
    class Program {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main(string[] args) {
            ExecutableServiceBase.Run(args, new ExampleThreadService());
        }
    }
}

  1. Change the default ExampleThreadService properties by opening it in the component designer (usually the default action of double clicking the service file in Solution Explorer).  Change ServiceName to “ExampleThreadService”. Change CanPauseAndContinue to “true”.
  2. Edit the ExampleThreadService code. Add a “using” for System.Threading and SoftWx.ServiceProcess. Change the parent class from ServiceBase to ThreadServiceBase. Delete the OnStart and OnStop methods. Add the OnWork method. When done, the entire class source should look like the code below.
// Copyright ©2012 SoftWx, Inc.
// Released under the MIT License the text of which appears at the end of this file.
// <authors> Steve Hatchett

using System;
using System.Threading;
using SoftWx.ServiceProcess;

namespace ServiceTest {
    partial class ExampleThreadService : ThreadServiceBase {

        public ExampleThreadService() {
            InitializeComponent();
        }

        private void InitializeComponent() {
            // 
            // ExampleThreadService
            // 
            this.CanPauseAndContinue = true;
            this.ServiceName = "ExampleThreadService";

        }

        // work method that simulates a long running method (one that runs for
        // the duration of the service). Typically, this kind of method would 
        // not use Sleep, but would block on some trigger source such as reading
        // from a MessageQueue, or waiting for a socket connection (for example).
        protected override void OnWork(SignalToken abortFlag, SignalToken continueFlag) {
            while (!abortFlag.IsSet) {
                if (continueFlag.IsSet) {
                    // simulate doing some work by writing out a message
                    WriteLogEntry("ThreadWork time=" + DateTime.Now.ToString("hh:mm:ss ffff"),
                        System.Diagnostics.EventLogEntryType.Information);
                    System.Threading.Thread.Sleep(3 * 1000); // simulate blocking on something
                } else {
                    // we've been paused - wait for signal to either continue or abort
                    WaitHandle.WaitAny(new WaitHandle[] { continueFlag.WaitHandle, abortFlag.WaitHandle });
                }
            }
        }
    }
}
Of course, this is just example code to show how it works. In real life you’d be blocking on something, and doing some real work. The ThreadServiceBase class handles the OnStart, OnStop, OnPause, and OnContinue methods, and wraps their essence into two signal flags that operate much like .Net’s CancellationToken. Your code can react to stopping, starting, pausing and continuing by interacting with abortFlag and continueFlag. All the OnXXXXX methods defined in ServiceBase are virtual, so your ThreadServiceBase descendant class is free to override them if you need to do some special processing. Just be sure to also call base.OnXXXX so it can do it’s thing too.

To see all the rest of the steps not specific to this framework, see the Microsoft walkthrough.

In the code for ThreadServiceBase, you can see how it handles the basic housekeeping of starting/stopping and pausing/continuing the service. In the OnStart, it creates and starts the thread that will be the main work thread for the life of the service. In the OnStop, it attempts to stop gracefully, requesting additional time from the service control manager if needed. Ideally though, it's ideal if your work method can respond quickly to a change in the abortFlag and exit the work method quickly.
// Copyright ©2012 SoftWx, Inc.
// Released under the MIT License the text of which appears at the end of this file.
// version 1.3 - 7/25/2012
// <authors> Steve Hatchett

using System;
using System.Diagnostics;
using System.Threading;

namespace SoftWx.ServiceProcess {
    /// <summary>
    /// 
    /// </summary>
    public class ThreadServiceBase : ExecutableServiceBase {
        private readonly SignalSource abortFlag = new SignalSource(); // flag used to signal worker method we need to stop
        private readonly SignalSource continueFlag = new SignalSource(); // flag used to signal worker method we can continue (i.e. not paused)
        private Thread workThread;

        /// <summary>
        /// Create a new instance of ThreadService
        /// </summary>
        public ThreadServiceBase() {
            this.abortFlag.Set(false);
            this.continueFlag.Set(true);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="abortFlag"></param>
        /// <param name="pauseFlag"></param>
        protected virtual void OnWork(SignalToken abortFlag, SignalToken pauseFlag) { }

        /// <summary>Start the work.</summary>
        protected override void OnStart(string[] args) {
            this.workThread = new Thread(new ThreadStart(Work));
            this.workThread.Start();
        }

        /// <summary>Stop the work.</summary>
        protected override void OnStop() {
            // indicate that we are stopping - this will signal
            // any worker code currently executing
            this.abortFlag.Set(true);
            var ticks = Environment.TickCount;

            // block until it's safe to exit
            bool cleanExit = true;
            while (!this.workThread.Join(10 * 1000)) {
                var elapsed = Environment.TickCount - ticks;
                if (elapsed >= MaxWaitSeconds * 1000) {
                    cleanExit = false;
                    break;
                }
                if (IsRunningAsService) {
                    this.RequestAdditionalTime(elapsed + (15 * 1000));
                }
                WriteLogEntry("Requesting additional time to stop", EventLogEntryType.Information);
            }
            ticks = Environment.TickCount - ticks;
            if (cleanExit) {
                WriteLogEntry("Worker method exited cleanly in " + ticks + " milliseconds", EventLogEntryType.Information);
            } else {
                WriteLogEntry("Worker method did not exit cleanly within " + ticks + " milliseconds", EventLogEntryType.Information);
            }
        }

        /// <summary>Pause the work.</summary>
        protected override void OnPause() {
            this.continueFlag.Set(false);
        }

        /// <summary>Continue the paused work.</summary>
        protected override void OnContinue() {
            this.continueFlag.Set(true);
        }

        private void Work() {
            try {
                OnWork(this.abortFlag.Token, this.continueFlag.Token);
            }
            catch (OperationCanceledException) { }
        }
    }
}

Tuesday, July 3, 2012

A Simple Framework for Windows Services 1 of 3

Source code for Service Framework posts.
I’ve had to write several windows services in the past. I developed a simple framework to make it easier to create and test windows service projects. The framework builds up a couple layers, with the innermost layer independent of the outer layers. So you can choose how much of the framework you want to use.
The inner layer is composed of the ExecutableServiceBase class. It puts in place behavior that automatically detects if the program is a debug build, and is UserInteractive, and if it is, runs the program as an interactive console application. If not, it assumes it has been invoked by Window’s Service Manager, and lets the code run as a service. This makes it very convenient to test the service by running it from Visual Studio during development. When run as a console application, standard input is monitored for single letter commands to simulate Service Manager events such as Pause, Continue, Stop, etc.
When using ExecutableServiceBase, your Windows service’s Program class is simplified to:
using SoftWx.ServiceProcess;

namespace ServiceTest {
    class Program {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main(string[] args) {
            ExecutableServiceBase.Run(args, new MyService());
        }
    }
}

The static ExecutableServiceBase.Run method expects an array of ExecutableServiceBase descendents, described a little further down. The Run method does the initial work of determining whether it’s being run as a service or a console app, and then gets the service started as needed for that environment.
// Copyright ©2012 SoftWx, Inc.
// Released under the MIT License the text of which appears at the end of this file.
// version 1.3 - 7/25/2012
// <authors> Steve Hatchett

using System;
using System.Diagnostics;
using System.ServiceProcess;

namespace SoftWx.ServiceProcess {
    /// <summary>
    /// Class for Windows Services, exposing methods that allow
    /// execution control outside of the normal ServiceController
    /// pattern. These methods can facilitate activities such as 
    /// running of services within a console app.
    /// </summary>
    public class ExecutableServiceBase : ServiceBase {
        private string[] programArgs;   // arguments that were passed into Program.Main
        private int maxWaitSecs = 120;  // maximum seconds to wait for Stop to complete

        /// <summary>
        /// Run the service. Depending on how it was started, it may
        /// run as a windows service, or, if the application is user
        /// interactive, and was compiled with DEBUG, then it's run
        /// as a console app.
        /// </summary>
        /// <param name="services">The services to be run.</param>
        public static void Run(params ExecutableServiceBase[] services) {
            Run(new string[0], services);
        }

        /// <summary>
        /// Run the service. Depending on how it was started, it may
        /// run as a windows service, or, if the application is user
        /// interactive, and was compiled with DEBUG, then it's run
        /// as a console app.
        /// </summary>
        /// <param name="services">The services to be run.</param>
        /// <param name="programArgs">The string array of arguments from Main method.</param>
        public static void Run(string[] programArgs, params ExecutableServiceBase[] services) {
            foreach (var service in services) service.programArgs = (string[]) programArgs.Clone();
            bool runAsService;
            bool debug = false;
#if DEBUG
            debug = true;
#endif
            runAsService = !(debug && Environment.UserInteractive);

            // if testing, run as console app, otherwise run as a Windows service
            if (runAsService) {
                ServiceBase.Run(services);
            } else {
                RunAsConsoleApp(services);
            }
        }

        /// <summary>
        /// Run the service within a console application.
        /// </summary>
        /// <param name="services">The services to be run.</param>
        private static void RunAsConsoleApp(ExecutableServiceBase[] services) {
            // for simpler testing, run as a console app
            Console.WriteLine("Starting services");
            foreach (var service in services) {
                service.OnStart(null);
            }
            Console.WriteLine("All services started");
            Console.WriteLine("Press P to Pause, C to Continue, S to Stop, D to Shutdown");
            Console.WriteLine("  PowerEvents: 0-BatteryLow, 1-OEM, 2-PowerStatusChange, 3-QuerySuspend,");
            Console.WriteLine("  4-QuerySuspendFailed,5-ResumeAutomatic, 6-ResumeCritical, 7-ResumeSuspend,");
            Console.WriteLine("  8-Suspend");
            bool running = true;
            while (running) {
                var key = Char.ToUpperInvariant(Console.ReadKey(false).KeyChar);
                Console.WriteLine();
                switch (key) {
                    case 'P':
                        foreach (var service in services) if (service.CanPauseAndContinue) service.OnPause();
                        break;
                    case 'C':
                        foreach (var service in services) if (service.CanPauseAndContinue) service.OnContinue();
                        break;
                    case 'S':
                        foreach (var service in services) if (service.CanStop) service.OnStop();
                        running = false;
                        break;
                    case 'D':
                        foreach (var service in services) if (service.CanShutdown) service.OnShutdown();
                        running = false;
                        break;
                    case '0':
                        foreach (var service in services) if (service.CanHandlePowerEvent) service.OnPowerEvent(PowerBroadcastStatus.BatteryLow);
                        break;
                    case '1':
                        foreach (var service in services) if (service.CanHandlePowerEvent) service.OnPowerEvent(PowerBroadcastStatus.OemEvent);
                        break;
                    case '2':
                        foreach (var service in services) if (service.CanHandlePowerEvent) service.OnPowerEvent(PowerBroadcastStatus.PowerStatusChange);
                        break;
                    case '3':
                        foreach (var service in services) if (service.CanHandlePowerEvent) service.OnPowerEvent(PowerBroadcastStatus.QuerySuspend);
                        break;
                    case '4':
                        foreach (var service in services) if (service.CanHandlePowerEvent) service.OnPowerEvent(PowerBroadcastStatus.QuerySuspendFailed);
                        break;
                    case '5':
                        foreach (var service in services) if (service.CanHandlePowerEvent) service.OnPowerEvent(PowerBroadcastStatus.ResumeAutomatic);
                        break;
                    case '6':
                        foreach (var service in services) if (service.CanHandlePowerEvent) service.OnPowerEvent(PowerBroadcastStatus.ResumeCritical);
                        break;
                    case '7':
                        foreach (var service in services) if (service.CanHandlePowerEvent) service.OnPowerEvent(PowerBroadcastStatus.ResumeSuspend);
                        break;
                    case '8':
                        foreach (var service in services) if (service.CanHandlePowerEvent) service.OnPowerEvent(PowerBroadcastStatus.Suspend);
                        break;
                }
            }
            Console.WriteLine("Services have been stopped/shutdown. Press any key to exit...");
            Console.ReadKey();
        }

        /// <summary>Gets the arguments passed in through Program.Main method.</summary>
        protected string[] ProgramArgs {
            get { return this.programArgs; }
        }

        /// <summary>Gets or sets the maximum number of seconds to wait for the service to stop cleanly.</summary>
        protected int MaxWaitSeconds {
            get { return this.maxWaitSecs; }
            set { this.maxWaitSecs = value; }
        }

        /// <summary>
        /// Gets a value indicating whether this ExecutableService is
        /// running as a Windows service. A value of false will be
        /// returned if this ExecutableService is running as a console
        /// application.
        /// </summary>
        public bool IsRunningAsService {
            get {
                return ((this.ServiceHandle != IntPtr.Zero)
                        || !Environment.UserInteractive);
            }
        }

        /// <summary>
        /// Write an entry to the event log if running as a servicer, or to the
        /// Console if running as a console application.
        /// </summary>
        /// <param name="message">The message to log.</param>
        /// <param name="entryType">The EventLogEntryType.</param>
        public virtual void WriteLogEntry(string message, EventLogEntryType entryType) {
            WriteLogEntry(message, entryType, 0);
        }

        /// <summary>
        /// Write an entry to the event log if running as a servicer, or to the
        /// Console if running as a console application.
        /// </summary>
        /// <param name="message">The message to log.</param>
        /// <param name="entryType">The EventLogEntryType.</param>
        /// <param name="eventId">The event Id.</param>
        public void WriteLogEntry(string message, EventLogEntryType entryType, int eventId) {
            if (IsRunningAsService) {
                WriteEventLogEntry(message, entryType, eventId);
            } else {
                Console.WriteLine(this.ServiceName + "(" + entryType.ToString() + ", Id=" + eventId + "): " + message);
            }
        }

        /// <summary>
        /// Write an entry to the event log.
        /// </summary>
        /// <param name="message">The message to log.</param>
        /// <param name="entryType">The EventLogEntryType.</param>
        /// <param name="eventId">The application-specific identifier for the event.</param>
        public virtual void WriteEventLogEntry(string message, EventLogEntryType entryType, int eventId) {
            EventLog.WriteEntry(message, entryType, eventId);
        }
    }
}

Normally, when you write a Windows service, you create a service class that descends from ServiceBase. To use the little service framework presented in this post, you make your service class inherit from ExecutableService instead. ExecutableService descends from ServiceBase, so you will get all of ServiceBase’s behavior. ExecutableService adds to that some additional behavior that deals with the fact that the service could be running as a service or a console app. In addition to a property that tells you if it's running as a service, there are two WriteLogEntry methods that can be used for basic logging. If the ExecutableService is being run as a service, the log messages are directed to the Windows event log. If it's being run as a console app, they are directed instead to standard output.
To use this class, include it in your service project, modify your program class as shown at the beginning of this post, change your service classes to descend from ExecutableServiceBase, and finally, set the Output type to Console Application on the Application tab of your service project properties.

In the next post I'll begin covering some of the other classes in this framework that build upon the ExecutableServiceBase class.

Sunday, July 1, 2012

Exploring C# LinkedLists via LRU Caches (3 of 3)

Downloads for post:
Long after I had deposited the LRU Cache (described in the previous post) into the library, I was poking around the guts of Dictionary<TKey, TValue> to get a better understanding of how it stored data internally. The implementation is pretty compact, and avoids creating a lot of extra objects for the contents of its internal collections.  When key/value pair is added, the HashCode of the key is mapped to a bucket, where the total number of buckets is the dictionary’s capacity. Each bucket is the head of a single linked list of all the entries added to the dictionary that mapped to the same bucked. All these single linked lists are contained in one big array of entry structs. Deletions are handled by maintaining a single linked list of free entry slots. The old LRU Cache I’d worked on before popped into my head, and it occurred to me that there might be some benefit in having it lean on a linked list that did not use objects for each node, but instead was implemented as an array of node structs.

You can’t just take a regular class implementation of a linked list, and simply replace “class” with “struct” in your node class. The reason is that classes use reference semantics, but structs use value semantics. What that means in practice is that a struct type variable is its own copy of the struct contents. If you say
SomeStruct a, b;
a = new SomeStruct();
a.SomeMember = 100;
b = a;
b.SomeMember = 50;

then a.SomeMember will be 100 and b.SomeMember will be 50. If you did the same thing with classes
SomeClass a, b;
a = new SomeClass();
a.SomeMember = 100;
b = a;
b.SomeMember = 50;

then a.SomeMember and b.SomeMember will both be 50. A struct variable holds a whole copy of a struct, not just a reference to it. If we simply change a node class to being a struct
struct LinkedNode {
    public string Value;
    public LinkedNode Previous;
    public LinkedNode Next;
}

then we make the compiler very grumpy. A LinkedNode variable would be a chunk of memory containig a string reference followed by a LinkedNode chunk of memory containing a string reference followed by a LinkedNode chunk of memory containing…ad infinitim. It just can’t work, and the compiler will let you know that. But there is another way.

What if we say that a LinkedNode struct always lives as an element in an array of LinkedNode structs, and that you refer to a node is by its array index? Then we can define a LinkedNode struct like this:
struct LinkedArrayNode {
    public string Value;
    public int PreviousIdx;
    public int NextIdx;
}

That will work - there's no problem making an array of those. Using this approach, I wrote a linked list class called LinkedArray that keeps its linked list as an array of structs, thus requiring no extra object creation for nodes. Then I wrote a third version of an LRU Cache called LruCacheSlim that uses a LinkedArray to store the cache contents.

LinkedArray


There are a few pieces that go into making LinkedArray work. There is the definition of the node struct which is just a value, the index of the previous node, and the index of the next node. The main piece is an array of these node structs. The size of the array is the LinkedArray’s capacity. Initially the capacity is all unused, so it will need to keep a count of how far into the array it has put active nodes. It needs to track the index of what is considered the head node (first in the linked list, although not necessarily the first position in the array). Once an active node has been placed in the array, I never want it to physically move within the array as a result of insertions or deletions. Block moving array elements will slow things down, and it’s important that nodes have completely stable locations since their index number is how they are referenced. So deletions will need to be handled by maintaining a free list of nodes that were active, but have been deleted. This list is a single linked list that acts like a stack. Finally, it needs to keep a count of items in the free list. When a new node is being inserted into the list, if the free list count is greater than 0 then the next free slot will be used and the free count decremented. Otherwise, the next virgin position in the unused capacity is used. The position of the next virgin position is the count of active nodes plus the free list count. The basic declaration of LinkedArray members looks like this:
public class LinkedArray<T> : ICollection<T>, IEnumerable<T>, IEnumerable {
    protected const int NullIdx = -1; // index value used to indicate null node (since nodes are structs, there is no true null node)
    protected const int FreeIdxMarker = -2;  // index value used in node's PreviousIdx to mark a node as a member of the free list

    private LinkedArrayNode[] nodes;// array of node structures
    private int head = NullIdx; // index of the head of the double linked list of active nodes (circular, so tail is previous to head, for easier maintenance)
    private bool circular;      // indicates whether linked list is presented to consumer as circular or not
    private int count;          // number of active nodes
    private int freeCount;      // number of nodes in the free list 
    private int freeIdx = FreeIdxMarker; // index of the head of single linked list of free nodes
    private int version;        // indicates modifications

    ... contstructors, properties, and methods ...
    
    private struct LinkedArrayNode {
        public T Value;
        public int PreviousIdx;
        public int NextIdx;

        internal LinkedArrayNode(T value) {
            this.Value = value;
            this.NextIdx = NullIdx;
            this.PreviousIdx = NullIdx;
        }
    }
}

The following diagram shows snapshots of how the LinkedArray looks immediately after the method to the right of that snapshot. These steps demonstrate how the LinkedArray works under the covers.



Granted, there is a some risk in using integer indexes to reference nodes rather than referencing objects. But the benefits may make it worth it. In particular, LinkedArray can be a useful component for building other collections, which is what I did with the LRU Cache.

LruCacheSlim


The implementation of LruCacheSlim is nearly the same as those described in the previous two posts, because from its viewpoint, LinkedArray is just a linked list, except instead of referencing node objects, it refers to node indexes. Rather than make this long post longer by pasting in the code, you can download it using the link at the top of this post.

In comparing LruCacheSlim with the two cache implementations in the previous two posts, how does it rate? For speed, it's somewhere in the middle between the previous two except for the operation of inserting items into a cache that hasn’t reached its capacity yet. In that case it displays a much more linear time profile, outperforming the other two versions handily where the cache capacity is very large (millions of items). Here are graphs comparing the three for the most common operations except for trying to get an item that doesn’t exist in the cache (where they are all nearly identical since all three just execute a lock and a Dictionary.TryGetValue).


This makes a few things apparent. First, they’re all pretty fast, and in the same ballpark. This is probably because most of the time they spend is from the lock{ } and Dictionary operations they all share in common. The first two versions that use objects for nodes have flatter lines for Adds where the new item replaces the oldest item (in a full cache), vs. Adds into a cache that hasn’t reached capacity. I think this is because once capacity has been reached, they stop creating new node objects, and after that just reuse the oldest node object that is getting dumped from the cache. For the very large cache sizes, the impact of creating all those node objects appears to increase the time cost of creating subsequent objects. But I’m speculating on that point.

Since they’re all pretty similar in speed, why bother using LruCacheSlim that uses LinkedArray? Besides speed, we should also consider memory. There is a cost associated with creating a bunch of node objects, but LinkedArray doesn’t suffer that cost. Because of that, LruCacheSlim consumes about 2/3 the overhead space of the other two for the same capacity. Another way of looking at that is if you feel like you can safely cache some number of Foo objects with LruCacheOrig or LruCache (from a memory consumption perspective), you could cache more Foos with LruCacheSlim. Being able to cache more items might substantially improve overall speed of the application using the cache, in a way not captured by how many nanoseconds faster one version’s operations are over another’s.