2009-03-31

My next new best friend

http://blogs.remobjects.com/blogs/ck/2009/02/06/p251

Read the comments I posted to see why I like it!

Unemployed

My employer's support contract has finally come to an end which means I have to look for another job, haven't had to do that in a while!

Drop me an email if you have any positions vacant, in the meantime it's time to do a little "networking".

2009-03-24

Unity - contexts

The outcome of this fairly long exchange on codeplex has made me very happy!

The BNP need my help


It seems they are unable to spell the word "money", because every time they send me their drivel of a newsletter they always want money. Usually it is for their "Van of truth" (which amuses me immensely) but this time it is to help them to become "the most technically advanced political party in the UK".
So, what are they going to do to earn this esteemed title?
  1. Set up our own BNP call centre
  2. Set up the party campaign central office
  3. Purchase 18 computers/screens/software
  4. Activate our brand new central database platform
  5. Recruit more staff to cope
  6. Train all staff in new systems
  7. Set up central mailing and telephone points for party
  8. Open our new logistical distribution warehouse
Riiight.
  1. Call centre – Surely other parties have these?
  2. Central office – I am pretty sure other parties have these!
  3. 18 computers / screens / software – Screens? Are they going to watch TV on them? MONITORS! At least we are talking I.T. now though.
  4. Central database platform – Most likely a list of names and addresses in MS Access, which is probably a nice upgrade from an Excel spreadsheet.
  5. Recruit staff – Not I.T. related.
  6. Train staff – A good idea!
  7. Mailing / telephone points – Get an address and a telephone?
  8. Warehouse – Bob's garage is too small for their Winston Churchill leaflets then?
If they think that is technologically advanced I had better not start my own political party, because my mobile phone is more technologically advanced than that, and it's broken!
I love the part where he says "This is a task of almost biblical proportions", brilliant! Nick Griffin has obviously not read The Bible! I can imagine Moses now. "Let my people go, or I will set up a small call centre with a telephone line, 8 computers with "Screens" and empty Bob's garage!"
As usual the entire thing is full of rubbish. Don't people realise that this party will never get into power, all they are doing is electing people into a system which will give them money for doing nothing at all?

2009-03-08

No Silverlight?

I'm trying to view this page in Firefox. When it loads the browser tells me I need Silverlight, so I download and install it and then restart my browser only to be told I need to install Silverlight.

That's not impressive at all!

2009-03-04

Delphi flickers

My app has a wizard approach, the current control appears within a panel with Align set to fill the hosting panel. My first wizard step control merely had an image on it which resizes with its parent control. When I resize the form the host panel resizes, which resizes the wizard control, which resizes the image; and boy does it flicker!

I just had to spend some time upgrading my old Delphi DIB controls to D2009 just to get an image that doesn't flicker, crazy! By the way, I tried the same thing in VS2008 and there was no flicker at all, and I thought Delphi was supposed to be the tool that produced fast UI apps.

2009-03-03

Synchronising downloads and updates (2)

There was a potential deadlock in the last piece of code. When you obtain any kind of lock you will mostly use a try..finally block to ensure the lock is released when you have finished with it. The using() command expands to a try..finally block so the original code might look okay, however if you mentally expand the code you will see the problem.

using (FileLockingService.FileReadLock(product1.ID))
{
    //Some code here
}

This becomes

var disposable = FileLockingService.FileReadLock(product1.ID);
try
{
    //Some code here
}
finally
{
    disposable.Dispose();
}

So why is this a problem? In a single threaded application it isn't, but this is a website so there are multiple threads running at the same time. Now take into account the fact that a web request has a timeout, what if the thread is aborted after the lock is obtained? Ordinarily this isn't a problem because the acquisition is followed immediately by a "try", but if we expand this code further it is evident that this isn't the case for the code I originally wrote. The code below is indented per method rather than the normal logical indendation

  • var disposable =
    • //Code inside FileLockingService
    • var lockHandler = GetLockHandler(int id);
    • lockHandler.EnterWriteLock();
      //The next command must be a try block
    • var enterWriteLockResult = new DisposableAction(..............); //Oops!
      • if (action == null) throw new ArgumentNullException("Action");
      • this.Action = action;
      • this.Context = context;
    • return enterWriteLockResult;
  • try
    {
        //Some code here
    }
    finally
    {
    disposable.Dispose();
    }

So here you see that rather than there being a TRY block immediately after the EnterWriteLock the code above would create a DisposableAction, check a parameter, assign two instance members, and then return a result. If anything went wrong at any of these points (OutOfMemoryException, ThreadAbortException, etc) then we'd end up with a lock that would not get removed. The code has been changed as follows.

    public class FileLockingService : IFileLockingService
    {
        readonly object SyncRoot = new object();
        readonly Dictionary<int, WeakReference> Locks = new Dictionary<int, WeakReference>();

        public ReaderWriterLockSlim GetLockHandler(int productId)
        {
            WeakReference resultReference;
            ReaderWriterLockSlim result;
            lock (SyncRoot)
            {
                if (Locks.TryGetValue(productId, out resultReference))
                {
                    result = (ReaderWriterLockSlim)resultReference.Target;
                    if (result != null)
                        return result;
                }
                result = new ReaderWriterLockSlim();
                Locks[productId] = new WeakReference(result);
            }
            return result;
        }
    }

and when I use this service:

    FileLockingService.GetLockHandler(product.ID).EnterReadLock();
    //.NET wont allow any exceptions until flow passes into the try block
    try
    {
        //This is the earliest point that an exception can occur after acquiring the lock
        using (var sourceStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            Response.ClearHeaders();
            Response.AddHeader("Content-Type", "Application/Binary");
            Response.AddHeader("Content-Disposition", "attachment; filename=" + product.ClientFileName);
            using (var resultStream = DownloadService.Process(currentUser, new List<string>(), product.ClientFileName, sourceStream))
            {
                int bytesRead;
                byte[] data = new byte[1024];
                while ((bytesRead = resultStream.Read(data, 0, data.Length)) > 0)
                    Response.OutputStream.Write(data, 0, bytesRead);
                Response.End();
            }//using
        }//filestream
    }
    finally
    {
        FileLockingService.GetLockHandler(product.ID).ExitReadLock();
    }

Lesson learned: When it comes to thread synchronisation don't do anything fancy!