Object Level Locking

Object Level Locking

Old forum URL: forums.lhotka.net/forums/t/1944.aspx


glenntoy posted on Monday, December 11, 2006

Has anyone thought of doing object level locking in CSLA version 2.0? Do you have any insights/theory on how to do pessimistic and optimistic locking in object level?

Thanks,
Glenn

RockfordLhotka replied on Monday, December 11, 2006

On a per-AppDomain basis, or across all users?

On a per-AppDomain basis this isn't too hard - you can create a directory object that tracks all the objects currently in memory, and then have all your factory methods use that directory object to either get the pre-existing object reference, or refuse to allow retrieval of the object because it already exists - whatever you choose.

That directory object is not overly complex - a multipart key of object type and object Id (from GetIdValue()) with a reference to the object itself.

The only complex part of the process is releasing the object so the directory knows to drop its references. You'll need a formal dereferencing scheme to make that work.

But solving this on a cross-user basis is really hard, because it requires a network-wide directory/locking service - and they are very hard to get right.

glenntoy replied on Monday, December 11, 2006

Across all users.
I think I wasn't clear in my 1st post but the idea you've responded is more or less on the idea we have in mind.

Below is a scenario on how we wanted to behave the object level locking:


We have created an initial design for this scenario, but we were not sure if this is the appropriate way on doing it. Below are the steps that we have in mind:
  1. We have a DB table (I think same as your directory) tblLockObject
  2. Every time the customer object is instantiated, it first check it exist in tblLockObject. If it doesn't exist then it creates an entry in tblLockObject saving the User, ObjectId, CreatedOn. If it does exist then the user can't edit/update the object.
  3. The entry in the tblLockObject will be remove when the customer object is destroyed.
  4. There will be a background processes that deletes the entries tblLockObject, in case it got orphaned

Are there any unforseen problems in this method?

DansDreams replied on Tuesday, December 12, 2006

I personally have never experienced concurrency issues that warrant something like that.  What I mean is for most applicaitons the likelihood in real life of having a write contention turns out to be quite low.  Low enough that optimistic concurrency checking with rowversion has been quite adequate.

As far as "problems", I think you've introduced fragility into the system (like when a tblLockObject gets orphaned) that for most applications has to be at least as bad as the concurrency problems it's trying to solve. 

That's my personal opinion and experience, YMMV.

 

P.S. - If you do have a need to go to that extreme, you probably want to take a hard look at the new Snapshot concurrency model in SQL 2005.  While I believe it would have to eat some resources on the server, I think it is really the only way to 100% guarantee concurrency integrity of the data itself.

 

ajj3085 replied on Tuesday, December 12, 2006

DansDreams:
As far as "problems", I think you've introduced fragility into the system (like when a tblLockObject gets orphaned) that for most applications has to be at least as bad as the concurrency problems it's trying to solve.


I have built a system were pessimistic locking was necessary.  The orphaned lock is not that big a deal, especially if you consider it up front and come up with ways to handle it.  Its not as fragile as you seem to think, and it has the benefit that it doesn't chew up a lot of server resources.

tetranz replied on Tuesday, December 12, 2006

If you implement some sort of system wide locking then remember that it needs to be multi-user safe. Its a classic computer science issue where you need an indivisible test and set operation. You can't have simple logic which says "If not locked then get lock" because someone else could sneek in between your test and set.

I've implemented this sort of thing safely (I think :) ) by making use of a unique index / primary key on a db table.  The primary key is the unique id of the object I want to lock, ie OrderId or whatever. There are also fields for user id and datetime. The db ensures that a maximum of one row per id can exist. My logic goes something like this.

1) Query the lock table for this object id. Who, if anyone has the lock?
2) If I already have the lock then nothing to do. Continue.
3) If someone else has the lock then goto 7
4) If nobody has the lock then try to insert row into the table with my user id. Catch any key violation errors.
5) If insert suceeded then I have the lock. Continue.
6) If insert failed, loop back to step 1.
7) Display a dialog saying "This has been locked by xxx since yyy". Give user the opportunity to override "if you really know that yyy has gone home or whatever ...". Also, give opportunity to cancel or open as read-only.
8) Make sure I still have lock when I save the object. Error if not (someone else overrode).
9) Delete the lock when I'm finished with the object. Therefore the situation in step 2 shouldn't normally happen.

Well, that's the basics of it. Everyone's situation is different but this works pretty well in my environment. I use it with a root / child / grandchild collection to edit where it really wouldn't be good to have more than one person editing at the same time.

Cheers
Ross

glenntoy replied on Tuesday, December 12, 2006

Thank you guys for your responses. I guess what your trying to say in the end to carefully handle the lock objects so they don't get orphaned.

DansDreams replied on Tuesday, December 12, 2006

I only mean that the orphaned locks could in fact be a HUGE deal if not handled properly.  Ross has provided some detail on one aspect of that.  IMO saying you need pessimistic locking because users are continually contending for records and the solution to orphaned locks is a 20 minute timeout seems self-contradictory.  I'm not trying to pick a fight with any of these ideas per se, especially since you report they're working, but only trying to point out they need to be considered carefully for any particular case rather than taken as a simple and easy fix by a casual reader.

I said "for most applications" meaning specifically when it's not really necessary (or very rarely so) you're paying a development and performance penalty for no significant benefit.

 

ajj3085 replied on Wednesday, December 13, 2006

DansDreams:
IMO saying you need pessimistic locking because users are continually contending for records and the solution to orphaned locks is a 20 minute timeout seems self-contradictory.


I have to disagree.  Orphaned locks shouldn't occur, but in the real world you have to account for them, especially in a web application.  The normal use case was that the user clicked the close link which unlocked the record.  In a forms application, you have the occasional crash which will orphan records.  In a web app, you don't have any such luxury. 

In the solution we implemented, session and login credentials expired after 20 minutes as well, which is why locks also expired at 20 minutes.

DansDreams:
I said "for most applications" meaning specifically when it's not really necessary (or very rarely so) you're paying a development and performance penalty for no significant benefit.


I agree, but that sentiment goes for pretty much anything you build into a system. 

ajj3085 replied on Tuesday, December 12, 2006

That sounds fine.  Actually, that's exactly what I did in a previous project, although it was not Csla based.

You may want to flesh out some use cases for locking, and have some BOs or at least some helper classes, that help handle the locking.

We also considered a process to clear orphaned locks, but we came up with another solution.  Basically locks would time out, so a lock more than 20 minutes old could be grabbed by anyone, and the original locker basically lucked out.  This was a web app though it may not be the best system for a forms app.

Oh, we also had an admin tool that allowed an administrator to delete any arbitrary lock.

HTH
Andy

Copyright (c) Marimer LLC