/// <summary> /// Clears the cache of the specified keys. /// </summary> /// <param name="keys">The keys to clear the cache of.</param> /// <param name="cleared"> /// Were the keys cleared successfully? /// </param> public void ClearKeys(IEnumerable <TKey> keys, out bool cleared) { var lockTaken = default(bool); try { Monitor.TryEnter(InstancesLock, LockTimeout, ref lockTaken); if (lockTaken) { foreach (var key in keys) { Instances.Remove(key); } cleared = true; } else { CacheSettings.FailedLockHandler(LockTimeout); cleared = false; } } finally { if (lockTaken) { Monitor.Exit(InstancesLock); } } }
/// <summary> /// Clears the cache. /// </summary> /// <param name="cleared"> /// Was the cache cleared successfully? /// </param> public void Clear(out bool cleared) { var lockTaken = default(bool); try { Monitor.TryEnter(InstancesLock, LockTimeout, ref lockTaken); if (lockTaken) { Instances.Clear(); cleared = true; } else { CacheSettings.FailedLockHandler(LockTimeout); cleared = false; } } finally { if (lockTaken) { Monitor.Exit(InstancesLock); } } }
/// <summary> /// Indicates whether or not an instance was cached by the specified keys. /// </summary> /// <param name="successful"> /// Was the check successful (e.g., wouldn't be successful if the lock /// timeout expired). /// </param> /// <param name="keys"> /// Optional. The keys to store/retrieve a value by. Each key combination will /// be treated as a separate cache. /// </param> /// <returns> /// True, if an item was cached by the specified keys; otherwise, false. /// </returns> public bool WasCached(out bool successful, params string[] keys) { var lockTaken = default(bool); try { Monitor.TryEnter(InstanceLock, LockTimeout, ref lockTaken); if (lockTaken) { successful = true; return(LastCache.HasValue ? Instances.ContainsKey(keys) : false); } else { CacheSettings.FailedLockHandler(LockTimeout); successful = false; return(false); } } finally { if (lockTaken) { Monitor.Exit(InstanceLock); } } }
/// <summary> /// Trys to get the value by the specified keys. /// </summary> /// <param name="keys"> /// The keys. /// </param> /// <param name="gotValue"> /// True, if an existing value was retrieved; otherwise, false. /// </param> /// <returns> /// The value, or the default for the type. /// </returns> private T TryGetByKeys(string[] keys, out bool gotValue) { var chosenKeys = keys ?? EmptyArray; var value = default(T); var lockTaken = default(bool); try { Monitor.TryEnter(InstanceLock, LockTimeout, ref lockTaken); if (lockTaken) { if (Instances.TryGetValue(chosenKeys, out value)) { gotValue = true; return(value); } else { gotValue = false; return(default(T)); } } else { CacheSettings.FailedLockHandler(LockTimeout); gotValue = false; return(default(T)); } } finally { if (lockTaken) { Monitor.Exit(InstanceLock); } } }
/// <summary> /// Trys to get the value by the specified keys. /// </summary> /// <param name="keys"> /// The keys. /// </param> /// <param name="accessKey"> /// The key to use to access the value. /// </param> /// <param name="gotValue"> /// True, if an existing value was retrieved; otherwise, false. /// </param> /// <returns> /// The value, or the default for the type. /// </returns> private T TryGetByKeys(string[] keys, TKey accessKey, out bool gotValue) { var chosenKeys = keys ?? EmptyArray; var value = default(T); var lockTaken = default(bool); try { Monitor.TryEnter(InstancesLock, LockTimeout, ref lockTaken); if (lockTaken) { var valueDictionary = default(Tuple <Dictionary <string[], T>, DateTime>); if (Instances.TryGetValue(accessKey, out valueDictionary)) { if (valueDictionary.Item1.TryGetValue(chosenKeys, out value)) { gotValue = true; return(value); } } } else { CacheSettings.FailedLockHandler(LockTimeout); } } finally { if (lockTaken) { Monitor.Exit(InstancesLock); } } gotValue = false; return(default(T)); }
/// <summary> /// Gets the instance variable (either from the cache or from the specified function). /// </summary> /// <param name="key"> /// The key to use when fetching the variable. /// </param> /// <param name="replenisher"> /// The function that replenishes the cache. /// </param> /// <param name="duration"> /// The duration to cache for. /// </param> /// <param name="defaultValue"> /// The value to use in the event that a value could not be retrieved (e.g., /// if the lock could not be achieved within the timeout). /// </param> /// <param name="gotValue"> /// Was the value retrieved, or was the default value used instead? /// </param> /// <param name="method"> /// Optional. The cache method to use when retrieving the value. /// </param> /// <param name="keys"> /// Optional. The keys to store/retrieve a value by. Each key combination will /// be treated as a separate cache. /// </param> /// <returns> /// The value. /// </returns> public T TryGet(TKey key, Func <TKey, T> replenisher, TimeSpan duration, T defaultValue, out bool gotValue, CacheGetMethod method = CacheGetMethod.Default, params string[] keys) { // Which cache retrieval method should be used? if (method == CacheGetMethod.FromCache) { // Get directly from cache. var lockTaken = default(bool); try { Monitor.TryEnter(InstancesLock, LockTimeout, ref lockTaken); if (lockTaken) { return(TryGetByKeys(keys, key, out gotValue)); } else { CacheSettings.FailedLockHandler(LockTimeout); gotValue = false; return(defaultValue); } } finally { if (lockTaken) { Monitor.Exit(InstancesLock); } } } else if (method == CacheGetMethod.NoCache) { // Get directly from replenisher. var returnValue = replenisher(key); gotValue = true; return(returnValue); } else { var lockTaken = default(bool); try { Monitor.TryEnter(InstancesLock, LockTimeout, ref lockTaken); if (lockTaken) { var tempInstance = default(T); var now = DateTime.Now; if (method == CacheGetMethod.Recache) { // Force the cache to replenish. tempInstance = replenisher(key); gotValue = true; UpdateValueByKeysWithoutLock(keys, key, tempInstance, now); } else { // Value already cached? var tempTuple = default(Tuple <Dictionary <string[], T>, DateTime>); if (Instances.TryGetValue(key, out tempTuple) && tempTuple.Item1.ContainsKey(keys)) { if (now.Subtract(Instances[key].Item2) >= duration) { if (method == CacheGetMethod.NoStore) { // Cache expired. Get a new value without modifying the cache. tempInstance = replenisher(key); gotValue = true; } else { // Cache expired. Replenish the cache. tempInstance = replenisher(key); gotValue = true; UpdateValueByKeysWithoutLock(keys, key, tempInstance, now); } } else { // Cache still valid. Use cached value. tempInstance = TryGetByKeys(keys, key, out gotValue); } } else { if (method == CacheGetMethod.NoStore) { // No cached value. Get a new value without modifying the cache. tempInstance = replenisher(key); gotValue = true; } else { // No cached value. Replenish the cache. tempInstance = replenisher(key); gotValue = true; UpdateValueByKeysWithoutLock(keys, key, tempInstance, now); } } } return(tempInstance); } else { CacheSettings.FailedLockHandler(LockTimeout); gotValue = false; return(defaultValue); } } finally { if (lockTaken) { Monitor.Exit(InstancesLock); } } } }
/// <summary> /// Gets the instance variable (either from the cache or from the specified function). /// </summary> /// <param name="duration"> /// The duration to cache for. /// </param> /// <param name="replenisher"> /// The function that replenishes the cache. /// </param> /// <param name="defaultValue"> /// The value to use in the event that a value could not be retrieved (e.g., /// if the lock could not be achieved within the timeout). /// </param> /// <param name="gotValue"> /// Was the value retrieved, or was the default value used instead? /// </param> /// <param name="method"> /// Optional. The cache method to use when retrieving the value. /// </param> /// <param name="keys"> /// Optional. The keys to store/retrieve a value by. Each key combination will /// be treated as a separate cache. /// </param> /// <returns> /// The value. /// </returns> public T TryGet(TimeSpan duration, Func <T> replenisher, T defaultValue, out bool gotValue, CacheGetMethod method = CacheGetMethod.Default, params string[] keys) { // Which cache retrieval method should be used? if (method == CacheGetMethod.FromCache) { // Get directly from cache. var lockTaken = default(bool); try { Monitor.TryEnter(InstanceLock, LockTimeout, ref lockTaken); if (lockTaken) { if (LastCache.HasValue) { var returnValue = TryGetByKeys(keys, out gotValue); return(returnValue); } else { gotValue = false; return(defaultValue); } } else { CacheSettings.FailedLockHandler(LockTimeout); gotValue = false; return(defaultValue); } } finally { if (lockTaken) { Monitor.Exit(InstanceLock); } } } else if (method == CacheGetMethod.NoCache) { // Get directly from replenisher. var returnValue = replenisher(); gotValue = true; return(returnValue); } else { var returnValue = defaultValue; var lockTaken = default(bool); try { Monitor.TryEnter(InstanceLock, LockTimeout, ref lockTaken); if (lockTaken) { // Variables. var now = DateTime.Now; // Force a cache update? if (method == CacheGetMethod.Recache) { UpdateValueByKeys(keys, replenisher()); } // Update cache if it's expired. else if (!LastCache.HasValue || !Instances.ContainsKey(keys) || now.Subtract(LastCache.Value) >= duration) { // Get new value? if (method == CacheGetMethod.NoStore) { returnValue = replenisher(); gotValue = true; return(returnValue); } // Update cache with new value. else { UpdateValueByKeys(keys, replenisher()); LastCache = now; } } // Return value. returnValue = TryGetByKeys(keys, out gotValue); return(returnValue); } else { CacheSettings.FailedLockHandler(LockTimeout); gotValue = false; return(defaultValue); } } finally { if (lockTaken) { Monitor.Exit(InstanceLock); } } } }