Rockford Lhotka
    CTO at Magenic
    Author, speaker, software architect
    Creator of the CSLA .NET framework

Home
Blog
CSLA .NET
Magenic
Speaking
Publications
About me
Contact me

Login

Concurrency techniques

 

The CSLA .NET architecture handles concurrency at the database level.

It doesn't address concurrency at the object level. Implementing object level concurrency in a distributed environment implies that you have a distributed lock manager. That is not only non-trivial, but also has a huge impact on performance, scalability and fault tolerance.

Addressing concurrency at the database level allows us to take advantage of pre-existing functionality and well-understood design patterns. This minimizes the impact on performance, scalability  and so forth.

In any case, only optimistic concurrency is supported. There is no practical way to implement pessimistic concurrency in a distributed environment (at least not without a distributed lock manager).

With optimistic concurrency there are two options:

  1. Last person to write wins
  2. First person to write wins

The easiest to implement is 'last write wins' because it requires no work on our part. This model also provides the highest performance. Implementing 'first write wins' has definite performance costs. This model is used in the book because I didn't have the space to cover the second option.

However, 'last write wins' is typically unacceptable, because it means that one user's data updates can be silently overwritten by another user.

So in most cases we want to use 'first write wins'. Implementing this is not overly difficult. There are three primary options (with many variations possible):

  1. Use a timestamp
  2. Use a CRC
  3. Use field comparisons

Timestamp

To implement the timestamp approach you need to add a timestamp column to every table in your database. Then in all your business classes you keep the timestamp value for the data in your object as a Private variable marked as <NotUndoable()>. If you have data in one object that comes from multiple tables, you may have multiple timestamps.

When you go to update or delete data (inserts are not affected) you must first retrieve the existing timestamp values for each row of data before updating that row. You compare the value in your object to the one in the table and only update if they match.

CRC

The CRC (cyclical redundancy check) approach is less invasive, as it doesn't require any changes to your database schema. This can be critical if your data is coming from preexisting databases or from non-database sources such as an XML file.

A CRC is a numeric value that is calculated based on a set of bytes of data. When you load data from the database into your object, you immediately calculate a CRC for all that data and store the CRC in your object as a Private variable marked as <NotUndoable()>. Even if your data came from multiple tables you probably have only one CRC.

When you go to update or delete data (inserts are not affected) you must first retrieve the existing data from each row and use it to calculate a CRC. You can then compare this CRC with the value in your object. If they match you allow the update to proceed.

Field comparisons

This approach has the highest overhead, but is the most powerful.

When you load data from the database into your object you also create a complete copy of each field into a second variable marked as <NotUndoable()>. In other words, if you retrieve a Name column you'd have two name variables:

Dim mName As String
<NotUndoable()> _
Dim mOriginalName As String

When you load the value of mName from the database you'd also load mOriginalName. From that point forward mOriginalName is never changed or used in any way.

When you go to update or delete data you must first retrieve the existing data from each row in the database. You compare that data field by field against your mOriginalxxx variables. If any are different AND the object's new value is different from the mOriginalxxx value you skip the update. In other words:

Dim currentName As String
 
' load currentName from database
 
If currentName <> mOriginalName AndAlso mOriginalName <> mName Then
  Throw New Exception("Concurrency violation, data not updated")
End If

This is more powerful than the timestamp or CRC approaches, because it allows interleaved updates, where users can concurrently update different fields of the same object without blocking each other.

 

(Updated 4/3/2003)