May 2006 Entries
metaCore Threading Gotcha

This one was biting webpoll - taken a while to track down, and it's the sort of thing that other people might be doing, so here's the deal:

Under the covers, metaCore holds a datarow (or an heirarchical collection of datarows for complex objects).  Each datarow is in turn associated with a datatable.  For objects that are returned from a single search, each of these datarows is associated with the same datatable (pretty much exactly as you'd expect).  Now, the DataTable object is not threadsafe under write operations (it's documented as such, so much as I'd like to, I can't really winge at MS).

The way that webpoll works is that it initially loads all of the nodes that are to be polled from the database.  It then kicks off a thread for ech node to perform the polling.  Periodically, each thread updates its node.  And periodically, it all goes bang :)

Since the node objects all came from a single search, they all shared the same underlying table, so the updates from the various threads were doing bad things under the covers.  Two possible fixes:

* The obvious one, but probably slower and prone to bugs: Stick "locks" around all updates. 

* The less obvious one: intead of doing "NODEList nl = NODE.Factory.Search()", do "NODEList nl = NODE.Factory.CreateListClone(NODE.Factory.Search())".  This takes advantage of a non-obvious consequence of doing a clone operation on a list - each of the objects in the cloned list have their own data table, rather than sharing.  At that point, thread safety is not an issue, since there is no shared state.

Obviously the Clone approach is slower up front, but for any long-running, multithreaded process, avoiding the locks is likely to be a good thing.  Plus locks are generally quite hard to code - you only need to miss one scenario, and the bug is still there (albeit less frequent, and hence harder to fix).

A third approach would be to make metaCore thread-safe on writes, but I've decided against this; thread safety is generally expensive to perform, and the scenarios in which this particular issue crops up are few and far between.  Hence I've opted for performance, and put the onus on you guys for thread safety :) 

Remember, this is only a problem is you have multiple threads *writing* to data objects that *were created from the same search*.  Read-only data caches are just fine, as is multiple threads writing to unrelated objects.

 

DBMail in SQL 2005

Just been fighting with the new DBMail features in SQL 2005, which no longer requires a MAPI profile to be setup.  Configuring the DBMail system itself is easy (from within Management Studio, go to Management / Database Mail and select "Configure Database Mail" from the context menu). 

SQL Agent jobs (and DB Maintenance plans) can then be configured to send emails to operators at appropriate times (to setup new operators, just go to SQL Server Agent / Operators from within Management Studio).

Once you've done this, you can happily send test emails by selecting "Send Test Email" from the Database Mail item. 

However, if you try to run any of your jobs, you'll find that no emails get sent.  Looking in the various logs, you may see entries such as "An attempt was made to send an email when no email session has been established".  This is easy to fix (once you know where to look!) - select Properties for SQL Server Agent, then go to the Alert System.  In there, you need to tick the "Enable mail profile" checkbox, and then restart SQL Server Agent.  This is the step that's taken me a while to track down, but now it's all working like a treat.