public virtual void Unlock(object key)
{
// Use Remove() instead of Get() because we are releasing the lock
// anyways.
var lockData = acquiredLocks.Remove(Convert.ToString(key)) as LockData;
if (lockData == null)
{
log.WarnFormat("attempted to unlock '{0}' but a previous lock was not acquired or timed out", key);
var unlockFailedEventArgs = new UnlockFailedEventArgs(
RegionName, key, lockKey: null, lockValue: null
);
options.OnUnlockFailed(this, unlockFailedEventArgs);
return;
}
log.DebugFormat("releasing cache lock: regionName='{0}', key='{1}', lockKey='{2}', lockValue='{3}'",
RegionName, lockData.Key, lockData.LockKey, lockData.LockValue
);
try
{
var db = GetDatabase();
// Don't use IDatabase.LockRelease() because it uses watch/unwatch
// where we prefer an atomic operation (via a script).
var wasLockReleased = (bool)db.ScriptEvaluate(unlockScript, new
{
lockKey = lockData.LockKey,
lockValue = lockData.LockValue
});
if (!wasLockReleased)
{
log.WarnFormat("attempted to unlock '{0}' but it could not be released (it maybe timed out or was cleared in Redis)", lockData);
var unlockFailedEventArgs = new UnlockFailedEventArgs(
RegionName, key, lockData.LockKey, lockData.LockValue
);
options.OnUnlockFailed(this, unlockFailedEventArgs);
}
}
catch (Exception e)
{
log.ErrorFormat("could not release cache lock: regionName='{0}', key='{1}', lockKey='{2}', lockValue='{3}'",
RegionName, lockData.Key, lockData.LockKey, lockData.LockValue
);
var evtArg = new ExceptionEventArgs(RegionName, RedisCacheMethod.Unlock, e);
options.OnException(this, evtArg);
if (evtArg.Throw)
{
throw new RedisCacheException(RegionName, "Failed to unlock item in cache. See inner exception.", e);
}
}
}