I'm working on a caching layer on a web server on the serverside, using Azure Shared Caching, to reduce the amount of requests to the database and thus make stuff run faster (hopefully). What I'm getting stuck on is how the make the whole endevour thread safe. I don't seem to find a reliable and usable way to lock keys in the DataCache. What I'm missing is a way to preemtively lock a key before there's anything stored on it, so that I could add a value without risk of another thread trying to do the same thing at the same time.
I have been looking exclusively at pessimistic locking so far, since that's how thread safety makes the most sense to me, I want to be sure that the stuff I'm working on is locked.
I have understood that if I am to use pessimistic locking, I am responsible for only using the methods related to that. Mixing things would mess up the whole locking mechanisms (source: 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);
The trouble is, "GetAndLock" throws an exception if I try to get something that isn't already in the cache. At the same time, my only method for adding something to the cache is "PutAndUnlock", and that one can't be used unless I did a successful "GetAndUnlock".
In effect, it is impossible to add anything new to the cache, only thing that can be done is replacing things that are already there (which will be nothing).
So it seems to me that I am forced to use the optimistic "Put" in the case where "GetAndLock" throws the nothing there exception. According to what I've read, though, the optimistic "Put" destroys any existing lock achieved with "GetAndLock", so that would destroy the whole attempt at thread safety.
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
Basicly the two threads could write different things to the same key at the same time, ignoring locks that they both think they have.
My only conclusion can be that the pessimistic locking of DataCache is feature incomplete and completely unusable. Am I missing something? Is there a way to solve this?
All I'm missing is a way to preemtively lock a key before there's anything stored on it.
forceLock
, where msdn says: If forceLock is true, key is locked irrespective of key-value pair presence in cache. Cant this helps you to lock key even when state does not exist for that key? – psulek