I was just reading over on Scott Bennett's block about CFLocking, and I wanted to touch on the issue a little bit myself. For a long time, I didn't use CFLock correctly. I had just learned about it, read the rules, and tried to apply them without ever thinking about what I was actually doing. Since I didn't know how important CFLock was, and how useful locking in an application can be, immediately I felt afraid and start using CFLock all over the place.
Scott Bennett lists these as the conditions of when you want to apply locking:
- Shared scope variables (variables in the application, server, and session* scopes
- Verity collections
- Files that are manipulated via CFFile or the ColdFusion File functions
These are good examples, but really, they can be condensed down into one category:
- Shared resources
This is what I was told when I first read about locking. The problem I had, was that no one qualified this. Scott Bennett does a good job of explaining CFLock and what the different types mean and offers some advice on how to reduce the number of locks that you use; but, I would like to take this one step further and really qualify WHEN a CFLock is necessary.
The way I see it, TWO conditions must be met in order to require the use of CFLock:
- A shared resource is being accessed or updated.
- There must be the possibility of a race condition resulting in a NEGATIVE outcome.
Point #2 is really what I think most discussions of CFLock lack and due to this lacking, many people (myself included) never really know or fully understood when to apply locking within an application. Point #2 is almost more important that point #1. A shared resource is only a potential place for locking, but a harmful race condition is really what determines if the locking is required.
Take, for example, the application DSN. Most of us persist the DSN data in some way within the APPLICATION scope, whether this is a direct storage (ex. APPLICATION.DSN) or storage via some cached singleton object (ex. APPLICATION.ServiceFactory.GetDSN()). DSN is persisted in a shared scope that is available to every user, and, if all you used for your locking was point #1 (shared resource), then you might assume that locking should be done around access to this variable.
But take a step back and think about the bigger picture (point #2). Is there a race condition? Absolutely! A site with thousands of concurrent users will most definitely run concurrent queries that require a reference to the APPLICATION.DSN object. But, and this is a HUGE BUTT (he he he he), does this race condition result in a negative outcome? Absolutely not! ColdFusion knows how to handle concurrent look-ups on Structs and will deal with synchronizing requests for you. Therefore, two users simultaneously trying to access APPLICATION.DSN will not result in an error, but rather, two successful reads.
Of course, that's just accessing; what if one request tried to access the APPLICATION.DSN object while another request tried to modify it? Here's where you really need to think about what your actual use-cases are. Is there ever going to be a time where:
- You change your APPLICATION.DSN in the middle of a page request.
- Locking would even prevent errors.
I am gonna take a strong stance and say that it is insanely rare that you are building an application that switches DSN information in the middle of page run. Therefore, that removes that use case (and therefore that negative outcome). Furthermore, even if tried to copy the DSN data into the REQUEST scope to prevent shared access, would that even stop errors from occurring? At that point, you might end up with queries that are using the wrong DSN data because they AREN'T referencing a shared resource.
Personally, the idea of switching DSN is ludicrous to me. But, application reinitialization is something that might occur from time to time. I'm talking about a situation where the entire APPLICATION scope is wiped out and repopulated. In this case, you might have a query that fails. But, here's where you really need to become the weigher of pros and cons; is it unacceptable for something to fail during reinitialization? This is something for you to decide for yourself, but I am gonna say, it is acceptable. On the very rare cases that I do have to reinitialize an application, I am fully comfortable with the thought that one or two people's pages might fail and they get our friendly, site-wide error handling page. To me, this extremely rare occurrence does NOT outweigh the cost of using CFLock around that particular resource.
This is just one example, but I want to drive home the point that locking should not be done blindly. Locking requires you to be a software engineer, not just a programmer; when going to apply CFLocks, you really have to think about what you are doing. Think about the consequences. Analyze whether or not race conditions are going to be harmful. Then, if you are convinced that enough harm is going to be done, apply the CFLock.