Pessimistic locking

P

Peter Morris

Hi all

I'm looking for a bit of feedback about a design, or maybe a suggestino for
an alternative implementation.

One of the services I need to implement is a pessimistic locking service.
Most objects edited in the system I am helping to write will use either a
last user wins approach or possibly a time stamp approach, it's not yet been
decided on that part but is easy to switch anyway. There are however about
3 or 4 complex structures which will take the user quite some time to edit
so it has been decided we will employ pessimistic locking for those objects.
I see two types of locks being required

01: WriteLock: Only 1 session can hold a write lock on an object (although
the same session could place more than 1 write lock).
02: RepeatableReadLock: Many sessions can hold one of these locks on an
object. If a write lock is already held on this object then the read lock
cannot be placed. If a read lock is already in place on an object then it
forbids a write lock.
03: If a user session times out then all locks held by that session should
be removed.

As the app server will (for the forseeable future) be a single machine I see
no reason to make the locks and sessions part of the business domain and
database. I was considering implementing the ILockingService and
ISessionService in the app layer, this way the business domain layer may use
the services without knowing how they are implemented. As the app will be
on a single server I thought I'd go for an in-memory solution to these
services.

Not many locks will be placed at the same time. Even RepeatableRead locks
wont be placed often, this is because they are used simply to prevent
writing so that the structure is unaltered as a complex read operation is
performed such as cloning a tree structure, and this wont happen too often
(maybe a few times per day). Write locks will occur more often, but only a
few hundred times per day so again not a huge demand.

To track locks I was thinking of using a specific lock class which holds a
Dictionary<SessionID, int> for the number of RepeatableRead locks and
another for the number of Write locks held per session. The lock objects
would be held in the service in a Dictionary<K, V> keyed on a persistent
unique identifier for each object. I was thinking of doing something like
this

private object SyncRoot = new Object();
public void Lock(IEnumerable<ILockable> objectsToLock)
{
lock (SyncRoot)
{
//01: Check if all locks may be acquired, if not then throw an
exception
//02: Place locks
}
}

Having the SyncRoot locked will cause a bottle neck but I don't expect it
will be prohibitive due to the low amount of locking, and it will prevent
deadlocks.

One of the things I don't like so much about the pseudo code above is that
it fails immediately if it cannot acquire all locks, whereas I'd prefer at
least a time out. So maybe.....

private object SyncRoot = new Object();
public void Lock(IEnumerable<ILockable> objectsToLock)
{
var startTime = DateTime.Now;
lock (SyncRoot)
{
while (true)
{
//01: Check if all locks may be acquired, if so then break out
of this loop
TimeSpan totalTimeTaken = DateTime.Now - startTime;
if (totalTimeTaken.TotalSeconds > 30)
throw ...............................;
Monitor.Wait(SyncRoot, TimeSpan.FromSeconds(1));
}
//02: Place locks
}
}

This would wait up to a maximum of X seconds to acquire the required locks
rather than failing immediately.

I'm just thinking "out loud" at the moment. I'm not starting to write this
until Monday morning but thought I'd post this in case anybody made some
good points that might affect my thoughts as I think up a solution :)


Thanks
 
A

Anthony Jones

Peter Morris said:
Hi all

I'm looking for a bit of feedback about a design, or maybe a suggestino
for an alternative implementation.

One of the services I need to implement is a pessimistic locking service.
Most objects edited in the system I am helping to write will use either a
last user wins approach or possibly a time stamp approach, it's not yet
been decided on that part but is easy to switch anyway. There are however
about 3 or 4 complex structures which will take the user quite some time
to edit so it has been decided we will employ pessimistic locking for
those objects.

You've lost me already on this. One usually chooses to _avoid_ pessimistic
locking if the edit is going to take some time by the user. In fact as soon
as human is involved optomistic locking would be indicated.

You must therefore have a different reason why you think pessimistic locking
is appropriate, what is that?
 
P

Peter Morris

The system I am working on has a kind of ClassInstance. This ClassInstance
has multiple InstanceProperty children associated with it

[ClassInstance] (Instance) 1------* (Properties) [InstanceProperty]

Because a user can easily spend more then 10 minutes editing one of these it
is undesirable to let two people start editing the same ClassInstance at the
same time. We don't want them to make modifications and then have to
perform some kind of conflict reconciliation later. Most of the system
employs a simple last user wins scenario, but for these long term operations
we want two types of locks

01: Exclusive lock write
This "checks out" the instance to the user exlusively.
02: Shared repeatible read lock
This merely prevents write locks being placed for a short duration so
that we know no changes occur whilst we do things like clone the instance +
its properties.
 
A

Anthony Jones

Peter Morris said:
The system I am working on has a kind of ClassInstance. This
ClassInstance has multiple InstanceProperty children associated with it

[ClassInstance] (Instance) 1------* (Properties) [InstanceProperty]

Because a user can easily spend more then 10 minutes editing one of these
it is undesirable to let two people start editing the same ClassInstance
at the same time. We don't want them to make modifications and then have
to perform some kind of conflict reconciliation later.

So thats the real reason for wanting some form of pessimistic lock. Its a
business decision, in this case it is deemed better to checkout an editable
instance to a user and prevent other users from editing (and I assume seeing
the current state of edits by the user who has the object checked out).

As you seem to have already established this would require some business
layer classes/interfaces to support the idea of an object being checked out
(or I'd think in terms of a "lease to edit").

Are you cloning the object for the presentation layer to edit?
 
P

Peter Morris

So thats the real reason for wanting some form of pessimistic lock. Its a
business decision, in this case it is deemed better to checkout an
editable instance to a user and prevent other users from editing (and I
assume seeing the current state of edits by the user who has the object
checked out).


DB->Domain objects->App layer->View model objects->Client

So no, other users wont see any of the changes until the Client sends back
the modified view model, the app layer updates the relevant domain objects,
and the changes are persisted; at which point the app layer will release the
lock.

There are about 4 different complex structure types in this app, all of
which need something more complex than a simple check in/out. Let's say the
structures are A,B,C,D

A is used as a template for B
B is used as a template for C
C is used as a template for D

If someone wants to create an instance of B from an instance of A then I
will place a repeatible read lock on A, this will prevent anyone from
placing a write lock on it but will allow multiple people to create B's from
the same A at the same time. If someone wants to edit an instance of A then
I will place a write lock on it, this prevents people from placing
repeatible read locks and write locks, so it locks it exclusively.

To achieve this I intend to have A,B,C,D realise an ILockable interface
which will merely return a unique ID for that object. An ILockingService
will then allow me to acquire/release these two types of locks on the
objects in question.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top