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
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