Jun
27

VS2010 Here we come (at last).

Finally got the go ahead to upgrade to VS2010 internally in our company, looking forward to getting to grips with the new IDE.

Jun
27

WIX (Windows Installer XML), Fabulous Free Resource

WIX @ http://wix.sourceforge.net/
Folks if you don’t know about this and are using .NET or any other technology for that matter. WIX is an Open Source utility for building Windows Installer Packages (msi’s that is). Save yourself 1,000′s  and move away from costly products like Install-Shield and Wise Installer, and get a community supported product that Microsoft themselves use for shipping SQL server and Office products. Works wonderfully within an automated build process also.

Jun
27

Relative path from 2 absolute paths

I was surprised to find that there is nothing built into the .NET framework to support this. So here is the code to give you back the relative path to a folder given two absolute paths.

public static string GetRelativePath(string fromAbsolutePath, string toAbsolutePath)
{
    // Ensure we have 2 absolute paths and switch to lower case for comparison.
    fromAbsolutePath = System.IO.Path.GetFullPath(fromAbsolutePath).ToLower();
    toAbsolutePath = System.IO.Path.GetFullPath(toAbsolutePath).ToLower();
    // If from and to are the same the return back the same folder characters.
    if (fromAbsolutePath == toAbsolutePath)
        return ".\\";

    // Split both paths and find the lowest common root.
    var fromSplits = fromAbsolutePath.ToLower().Split(System.IO.Path.DirectorySeparatorChar);
    var toSplits = toAbsolutePath.ToLower().Split(System.IO.Path.DirectorySeparatorChar);
    var commonRoot = -1;
    for (var i = 0; i < Math.Min(fromSplits.Length, toSplits.Length); i++)
    {
        if (fromSplits[i] == toSplits[i])
            commonRoot = i;
        else
            break;
    }
    // No common root, so on different drives or shares, so give out absolute path of the to folder.
    if (commonRoot == -1)
        return toAbsolutePath;
    // Build up the path from the lowest from folder to the common root, and then extend out the
    // path with the remainer of the to path.
    var fromRelative = new StringBuilder();
    for (var i = (commonRoot + 1); i < fromSplits.Length; i++)
        fromRelative.Append("..\\");
    for (var i = (commonRoot + 1); i < toSplits.Length; i++)
        fromRelative.Append(toSplits[i]).Append("\\");
    return fromRelative.ToString();
}

May
23

Resource locking using soft locking strategy.

Summary

Here we outline an approach to distributed resource locking strategy where a shared database is available. It utilizes an non transactional database locking mechanism.
All code is available for download from here ; please note the sample database and source code are in separate files.

Discussion

This mechanism has been used to lock many different types of resources like directories, files, devices, mail boxes and more. It is particularly useful in an Active-Active server deployment where many instances of the same service are running and sharing the work load between them for load balancing or resilience reasons.
It is also very useful to be able to see who/what has a resource locked,  on which server/instance it was locked and for how long.

Resource allocation and deallocation

The resource allocation and deallocation are all managed within a using statement. There are just a few points that need to be taken into consideration.

  • In the example each instance of an application is represented by a unique identifier.
  • Resource access is based upon unique keys for each resource.
  • You need to ensure that the key generation mechanism for a resource uses the same algorithm across all your servers.

Example

var lockKey = string.Format("BatchProcessor-{0}", _batch_id);
using (var sl = new softlocks.lib.SoftLock(lockKey, Program.INSTANCE_ID, "BatchProcessor", _batch_id.ToString(), _identity, true))
{
   var thread_id = System.Threading.Thread.CurrentThread.ManagedThreadId;
   if (sl.IsLocked())
   {
      Console.WriteLine("Resource {0} has been locked by thread {1}", sl.Resource, thread_id.ToString());
      System.Threading.Thread.Sleep(1000);
   }
   else
   {
      Console.WriteLine("Failed lock on resource {0} by thread {1}", sl.Resource, thread_id.ToString());
   }
}

Recovery

In very exceptional situations it is possible that lock records are left in the database. This may happen if say the server looses power during the resource allocation using block and the dispose never got called. In situations like this when the service starts up again we automatically clear all existing locks that the service already held. We also have monitors which detect when the services are not available anymore and release any locks that may have been held by that service. The 1st portion of this is covered in the example; where in the main program the existing (if any) instance locks are cleared.

May
06

Parallel Tasks and System.ThreadPool Exhaustion

Came across an interesting situation today where we noticed severe performance degradation in one of our components which is part of an overall product we ship.
It turns out that we had parallel tasks, and each sub tasks was executing other parallel tasks and those sub tasks were executing other parallel tasks and at each stage we were waiting on the set of parallel tasks to complete.
Each parallel task gets submitted to the System.ThreadPool; and as you all know the thread pool will only execute a certain number of tasks at once.
So once the thread pool reached that limit; each of the inner most tasks could only complete when another task had complete and was scheduled for execution by the Thread Pool; this basically lead to serial execution of tasks when the TP was filled.

The Moral of this Story

Be aware when using Parallel tasks which run on the thread pool; that you may end up running things serially if you embed parallel tasks in parallel tasks.

Resolution
We removed the 3rd level of parallel tasks and executed them serially as they were light weight task and should never have been put in to run in parallel anyway. This reduced by a factor of 3 the number of parallel tasks executing in the thread pool; so contention was reduced to an acceptable level.
Also test, test and test; and when you spot something odd; try and understand it. I spent the best part of a day resolving this issue and getting a grip with what was going on. But from the point of not having an embarrassing situation arise on a customers site; in a production environment and having to explain it I think it was time well spent.

May
06

Checking out Blogs on DotNetKicks

Looking cool. Might start publishing some bits shortly.