2013-03-12 1 views
3

Я работаю над слоем кеширования на веб-сервере на сервере, используя совместное кеширование Azure, чтобы уменьшить количество запросов к базе данных и, таким образом, сделать работу быстрее (надеюсь). То, что я застрял в том, как сделать весь endevour поток безопасным. Кажется, я не нашел надежного и удобного способа блокировки ключей в DataCache. То, что мне не хватает, - это способ предварительно заблокировать ключ, прежде чем на нем что-нибудь сохранится, чтобы я мог добавить значение без риска другого потока, пытающегося сделать то же самое в одно и то же время.Добавление элемента в Microsoft.ApplicationServer.Caching.DataCache с пессимистической блокировкой?

Я смотрю исключительно на пессимистическую блокировку до сих пор, так как это то, как безопасность потоков имеет для меня наибольший смысл, я хочу быть уверенным, что материал, над которым я работаю, заблокирован.

Я понял, что если я использую пессимистическую блокировку, я несу ответственность за использование только тех методов, которые связаны с этим. Смешивание вещей испортило бы все механизмы блокировки (источник: http://go4answers.webhost4life.com/Example/datacacheput-unlocking-key-77158.aspx).

So basicly I only have access to these methods: 
value GetAndLock(key, out DataCacheLockHandle); 
void PutAndUnlock(key, value, DataCacheLockHandle); 
void Unlock(key, DataCacheLockHandle); 

Беда в том, «GetAndLock» бросает исключение, если я пытаюсь получить то, что не в кэше. В то же время мой единственный способ добавить что-то в кеш - это «PutAndUnlock», и его нельзя использовать, если я не сделал успешный «GetAndUnlock».

Фактически, невозможно добавить что-либо новое в кэш, но только то, что можно сделать, это заменить те вещи, которые уже есть (что ничего не будет).

Так что мне кажется, что я вынужден использовать оптимистичный «Путь» в случае, когда «GetAndLock» выбрасывает исключение. В соответствии с тем, что я прочитал, оптимистичный «Путь» уничтожает любой существующий замок, достигнутый с помощью «GetAndLock», чтобы уничтожить всю попытку безопасности потока.

Example plan: 
1. Try to GetAndLock 
2. In case of nothing there exception: 
    - Put a dummy item on the key. 
    - GetAndLock again. 
3. We have a lock, do computations, query database etc 
4. PutAndUnlock the computed value 


One of probably several ways it would screw up: 
Thread1: Tries to GetAndLock, gets nothing there exception 
Thread2: Tries to GetAndLock, gets nothing there exception 
Thread1: Put a dummy item on the key 
Thread1: GetAndLock again, lock achieved 
Thread2: Put a dummy item on the key (destroying Thread1:s lock) 
Thread2: GetAndLock again, lock achieved 
Thread1: We think we have a lock, do computations, query database etc 
Thread2: We have a lock, do computations, query database etc 
Thread1: PutAndUnlock the computed value (will this throw an exception?) 
Thread2: PutAndUnlock the computed value 

В основном две нити могут писать разные вещи одному и тому же ключу в одно и то же время, игнорируя блокировки, которые оба они считают.

Мое единственное заключение заключается в том, что пессимистическая блокировка DataCache является неполной и полностью непригодной для использования. Я что-то упускаю? Есть ли способ решить это?

Все, что мне не хватает, - это способ предварительно заблокировать ключ, прежде чем что-нибудь сохранится на нем.

+0

GetAndLock имеет параметр 'forceLock', где говорит MSDN: Если forceLock правда, ключ заблокирован независимо присутствия пары ключ-значение в кеше. Не может это помочь вам заблокировать ключ, даже если для этого ключа не существует состояния? – psulek

ответ

0

Джонатан,

Вы рассматривали эту логику для добавления вещей в кэш (простите пожалуйста мой псевдо-код)?

общественного BOOL AddToCache (строка ключ, значение объекта) {

DataCache dc = _factory.GetDefaultCache(); 
object currentVal = dc.Get(key); 

if (currentVal == null) { 
    dc.Put(key, value); 
    currentVal = dc.GetAndLock(key); 

    if (value == currentVal) { 
     //handle this rare occurrence + unlock. 
     return false; 
    } else { 
        dc.Unlock(key); 
      } 
} else { 
    currentVal = dc.GetAndLock(key); 
    dc.PutAndUnlock (key, value); 
} 

return true; 

}

+0

Я не уверен, что я следую за этим. Вы имеете в виду добавить код для обработки случая, когда блокировка была прервана? –

+0

Хмм, читая его снова, я предполагаю, что это не значит. Проблема с попыткой получить, чтобы проверить, нет ли ключа, что другой поток может сделать то же самое, пока вы работаете, так что вы могли бы увеличить два потока паралелей, делающих Put. Этот Put может потенциально уничтожить приобретенный GetAndLock другого потока. –

+0

Идея заключается в следующем: \t 1. сделать добираетесь, чтобы видеть, если он существует \t 2. если он не существует добавить его \t 3. проверить его еще раз (с замком) \t 4. если новое значение НЕ равнозначает значение, которое вы только что добавили, затем какой-то другой поток изменил его между вами, проверяя, существовало ли значение и до того, как вы положили на него блокировку ->, поэтому вам придется добавить некоторую логику для обработки этой ситуации. – SemanticZen