Некоторый контекст для вопроса
- Все объекты в этом вопросе являются постоянными.
- Все запросы будут поступать от клиента Silverlight, который обращается к серверу приложений по двоичному протоколу (Hessian), а не по WCF.
- У каждого пользователя будет сеансовый ключ (не сеанс ASP.NET), который будет строкой, целым числом или GUID (пока не определено).
Для редактирования некоторых объектов может потребоваться много времени (30 или более минут), поэтому мы решили использовать пессимистическую автономную блокировку. Пессимистично, потому что необходимость согласовывать конфликты была бы слишком раздражающей для пользователей, в автономном режиме, потому что клиент не постоянно подключен к серверу.
Вместо того, чтобы хранить информацию о блокировке сеанса / объекта в самом объекте, я решил, что любой агрегатный корень, у которого могут быть заблокированы его экземпляры, должен реализовывать интерфейс ILockable
public interface ILockable
{
Guid LockID { get; }
}
Этот LockID будет идентификатором объекта "Lock", который содержит информацию о том, какой сеанс его блокирует.
Теперь, если бы это была простая пессимистическая блокировка, я смог бы добиться этого очень просто (используя увеличивающийся номер версии в Lock для выявления конфликтов обновлений), но мне действительно нужна пессимистическая автономная блокировка ReaderWriter.
Причина в том, что некоторые части приложения будут выполнять действия, которые читают эти сложные структуры. К ним относятся такие вещи, как
- Чтение одной структуры для ее клонирования.
- Чтение нескольких структур для создания двоичного файла для «публикации» данных во внешнем источнике.
Блокировки чтения будут удерживаться в течение очень короткого периода времени, обычно менее секунды, хотя при некоторых обстоятельствах они могут удерживаться примерно 5 секунд при предположении.
Блокировки записи в основном будут храниться в течение длительного времени, поскольку они в основном удерживаются людьми.
Существует высокая вероятность того, что два пользователя попытаются отредактировать один и тот же агрегат одновременно, и высокая вероятность того, что многим пользователям также потребуется временная блокировка чтения одновременно. Я ищу предложения относительно того, как я мог бы реализовать это.
Еще одно замечание: если я хочу установить блокировку записи и есть некоторые блокировки чтения, я бы хотел поставить в очередь блокировку записи, чтобы новые блокировки чтения не устанавливались. Если блокировки чтения удаляются в течение X секунд, тогда получается блокировка записи, если нет, то блокировка записи снимается; новые блокировки чтения не будут помещены, пока блокировка записи находится в очереди.
Пока у меня есть эта идея
- Объект Lock будет иметь номер версии (int), поэтому я могу обнаруживать конфликты при многократном обновлении, перезагрузить, попробовать еще раз.
- У него будет строка [] для блокировки чтения
- Строка для хранения идентификатора сеанса с блокировкой записи
- Строка для хранения блокировки записи в очереди
- Возможно, счетчик рекурсии позволяет многократно блокировать один и тот же сеанс (как для блокировки чтения, так и для записи), но пока не уверен в этом.
Правила:
- Невозможно установить блокировку чтения, если есть блокировка записи или блокировка записи в очереди.
- Невозможно установить блокировку записи, если есть блокировка записи или блокировка записи в очереди.
- Если блокировок вообще нет, то можно установить блокировку записи.
- Если есть блокировки чтения, тогда блокировка записи будет поставлена в очередь вместо полной блокировки записи. (Если по истечении времени X блокировки чтения не исчезают, блокировка отключается, в противном случае она обновляется).
- Не удалось поставить в очередь блокировку записи для сеанса с блокировкой чтения.
Кто-нибудь может увидеть какие-либо проблемы? Предложить альтернативы? Что-нибудь? Буду признателен за обратную связь, прежде чем принять решение о том, какой подход выбрать.