Thursday, January 06, 2005

I just got finished debugging a crazy problem with some C# code.  This particular code is part of an application that deals with file spooling, and it deals with alot of ambiguous file locking issues by always locking greedily.  Any spooling task that is unable to gain an exclusive lock on a file simply assumes another thread must be working on the file and it leaves it alone.

The developer used a pattern that handles System.IO.IOException and assumes that any IOException must be because of a concurrency issue.  The problem with this is that there are lots of calls that can cause file IO that you may be unaware of.  In this case, there was an assembly binding issue caused by some plugin-style dynamic loading that was throwing System.IO.FileLoadException (Which actually seems to be out of place as a subclass of IOException since it is specific to assembly loading and not IO in general).  The pattern in the code was assuming that, in general, any IOException was not an exceptional event and signified another condition. So, the task never did any work and never reported the exceptional condition.

Eric Gunnerson wrote a nice overview piece on exceptions in C# on msdn.  Some of his guidelines are

Catch the most specific exception

If your code needs to recover from some exceptions, make sure to catch only those exceptions. If you catch more general ones, it's more likely you'll mistakenly swallow exceptions you don't want to swallow.

Only swallow if you're sure

This is really a corollary of the previous guideline. When you swallow an exception, your saying that you understand all cases where this exception could arise, and that the recovery code you're writing handles all of those cases.

Use lock or using if applicable

If you can use the lock or using statements, use them. They make the code more readable and make it more likely you'll do the right thing.

Wrap exceptions if applicable

If you can add additional information to an exception, by all means do so. If I pass a parameter on to another function, it might be useful for me to add additional information about the parameter.

The first two here are obviously directly applicable to the scenario, and would have at least raised some flags if I had first checked all the IOExceptions to see what they encompass.  The solution for me was to take a look at the pattern and reduce the scope of the IOException catches to only those statements that I expected might throw the exception for locking.

[UPDATE] I wanted to note that the exception handling pattern worked great until it was extended by me to a more complicated scenario involving dynamic assembly loading.

posted on Thursday, January 06, 2005 11:05:29 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]
Related posts:
9-year Anniversary (yesterday)
LinqToStdf now on CodePlex
Image Slicer for Deep Zoom in Silverlight 2
Silverlight limitations and Constrained Callvirt in IL
Happy Birthday Peter
What are the generic Delegates in the framework for?
Tracked by:
"electric tool accessories" (electric tool accessories) [Trackback]
"foto ose" (foto ose) [Trackback]
"freepops" (freepops) [Trackback]
"camcorder xxx.com" (camcorder xxx.com) [Trackback]
"posing stool" (posing stool) [Trackback]
"second income ideas" (second income ideas) [Trackback]
"good looking idraulico" (good looking idraulico) [Trackback]
"legal aid society" (legal aid society) [Trackback]
"alternative school programs" (alternative school programs) [Trackback]
"snowmobile helmets" (snowmobile helmets) [Trackback]
"custom plaque drop ship" (custom plaque drop ship) [Trackback]
"usa flag" (usa flag) [Trackback]
"credit repair agency" (credit repair agency) [Trackback]
"Force Outboard Motor Parts" (Force Outboard Motor Parts) [Trackback]
"tuxedo 8.1 solaris 5.9 compile" (tuxedo 8.1 solaris 5.9 compile) [Trackback]
"unimi" (unimi) [Trackback]
"high scope curriculum" (high scope curriculum) [Trackback]
"used car dealers milwaukee wisconsin" (used car dealers milwaukee wisconsin) [Trackback]
"Prepaid Wireless Providers" (Prepaid Wireless Providers) [Trackback]
"idaho building inspector training" (idaho building inspector training) [Trackback]
"dlp televisions" (dlp televisions) [Trackback]
"music websites" (music websites) [Trackback]
"essay examples" (essay examples) [Trackback]
"premium sms business model" (premium sms business model) [Trackback]
"pelotto" (pelotto) [Trackback]
"seggiolino bicicletta" (seggiolino bicicletta) [Trackback]
"photos of couple erotic massage" (photos of couple erotic massage) [Trackback]
"hookers whores" (hookers whores) [Trackback]
"aol and vpn connections" (aol and vpn connections) [Trackback]
"boys smelly sneakers" (boys smelly sneakers) [Trackback]
"zinc propecia" (zinc propecia) [Trackback]
Friday, January 07, 2005 11:53:21 PM (Pacific Standard Time, UTC-08:00)
Wow that *is* insightful =) There are actually several subclasses of IOException that might need to be checked, besides FileLoadException.

One thing Microsoft did right in Windows is kernel-managed file locking. Well, ok, sometimes the locks don't get cleaned up, but the concept is a good one. On most UNIXes, file locks can be ignored and you can't open a file exclusively in most cases. (Maybe Linux has this now, maybe I should write a kernel module!) AFAIK the only way to know if a file is locked using .NET framework is to open it, and catch an IOException.

It sure would be nice if Microsoft made a specialized IOException for trying to open a locked file.

Better still would be a way to test for a lock without the overhead of an exception. I wonder if there's a way to do it thru P/Invoked Win32 API calls...
Saturday, January 08, 2005 10:13:16 AM (Pacific Standard Time, UTC-08:00)
I'll have to check to see if 2.0 supports such a check as well.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):