2

Some context for the question

  • All objects in this question are persistent.
  • All requests will be from a Silverlight client talking to an app server via a binary protocol (Hessian) and not WCF.
  • Each user will have a session key (not an ASP.NET session) which will be a string, integer, or GUID (undecided so far).

Some objects might take a long time to edit (30 or more minutes) so we have decided to use pessimistic offline locking. Pessimistic because having to reconcile conflicts would be far too annoying for users, offline because the client is not permanently connected to the server.

Rather than storing session/object locking information in the object itself I have decided that any aggregate root that may have its instances locked should implement an interface ILockable

public interface ILockable
{
  Guid LockID { get; }
}

This LockID will be the identity of a "Lock" object which holds the information of which session is locking it.

Now, if this were simple pessimistic locking I'd be able to achieve this very simply (using an incrementing version number on Lock to identify update conflicts), but what I actually need is ReaderWriter pessimistic offline locking.

The reason is that some parts of the application will perform actions that read these complex structures. These include things like

  • Reading a single structure to clone it.
  • Reading multiple structures in order to create a binary file to "publish" the data to an external source.

Read locks will be held for a very short period of time, typically less than a second, although in some circumstances they could be held for about 5 seconds at a guess.

Write locks will mostly be held for a long time as they are mostly held by humans.

There is a high probability of two users trying to edit the same aggregate at the same time, and a high probability of many users needing to temporarily read-lock at the same time too. I'm looking for suggestions as to how I might implement this.

One additional point to make is that if I want to place a write lock and there are some read locks, I would like to "queue" the write lock so that no new read locks are placed. If the read locks are removed withing X seconds then the write lock is obtained, if not then the write lock backs off; no new read-locks would be placed while a write lock is queued.

So far I have this idea

  1. The Lock object will have a version number (int) so I can detect multi-update conflicts, reload, try again.
  2. It will have a string[] for read locks
  3. A string to hold the session ID that has a write lock
  4. A string to hold the queued write lock
  5. Possibly a recursion counter to allow the same session to lock multiple times (for both read and write locks), but not sure about this yet.

Rules:

  • Can't place a read lock if there is a write lock or queued write lock.
  • Can't place a write lock if there is a write lock or queued write lock.
  • If there are no locks at all then a write lock may be placed.
  • If there are read locks then a write lock will be queued instead of a full write lock placed. (If after X time the read locks are not gone the lock backs off, otherwise it is upgraded).
  • Can't queue a write lock for a session that has a read lock.

Can anyone see any problems? Suggest alternatives? Anything? I'd appreciate feedback before deciding on what approach to take.

4

3 回答 3

1

您是否考虑过mvcc实现:

当然,这将更难实现,但似乎比你所解释的要并发得多。只是把想法扔在那里。

于 2009-02-11T19:53:27.920 回答
1

(编辑成更多的措辞作为答案,而不是一堆问题)

我也在雅虎 DDD 列表上对此进行了回复,但为了完整起见,也不妨在这里。

您没有明确提到(我可以看到)任何类型的写锁超时。我知道他们将能够被持有很长时间,但有某种超时(即使它带有通知)将是一个谨慎的策略。

除此以外(甚至除此之外),如果您还没有考虑过,您可能需要考虑使用一种手动释放锁的方法 - 取决于系统的用户/角色,可能是某种易于操作的方法- 使用管理界面。

此外,您无疑也想到了这一点,请确保读锁数组是线程安全的。

于 2009-02-12T00:41:56.087 回答
0

如果您真的想滚动自己的锁定,我会遵循类似于线程锁定的锁定模式,例如在 ReaderWriterLockSlim 中。

http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx

于 2009-02-24T22:43:08.500 回答