2013-08-12 15:06:12 +02:00
|
|
|
|
using System;
|
2014-05-27 12:16:41 +02:00
|
|
|
|
using System.Collections;
|
2013-08-12 15:06:12 +02:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Core.Cache
|
|
|
|
|
|
{
|
2013-12-16 16:21:38 +11:00
|
|
|
|
internal abstract class DictionaryCacheProviderBase : ICacheProvider
|
2013-08-12 15:06:12 +02:00
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
// prefix cache keys so we know which one are ours
|
|
|
|
|
|
protected const string CacheItemPrefix = "umbrtmche";
|
|
|
|
|
|
|
2014-05-22 09:36:08 +02:00
|
|
|
|
protected readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
|
2014-05-27 12:16:41 +02:00
|
|
|
|
|
|
|
|
|
|
// manupulate the underlying cache entries
|
|
|
|
|
|
// these *must* be called from within the appropriate locks
|
|
|
|
|
|
// and use the full prefixed cache keys
|
|
|
|
|
|
protected abstract IEnumerable<DictionaryEntry> GetDictionaryEntries();
|
|
|
|
|
|
protected abstract void RemoveEntry(string key);
|
|
|
|
|
|
protected abstract object GetEntry(string key);
|
|
|
|
|
|
|
|
|
|
|
|
protected string GetCacheKey(string key)
|
|
|
|
|
|
{
|
|
|
|
|
|
return string.Format("{0}-{1}", CacheItemPrefix, key);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-06-17 18:42:00 +02:00
|
|
|
|
protected object GetSafeLazyValue(Lazy<object> lazy)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
return lazy.Value;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-05-27 12:16:41 +02:00
|
|
|
|
#region Clear
|
|
|
|
|
|
|
2013-08-12 15:06:12 +02:00
|
|
|
|
public virtual void ClearAllCache()
|
|
|
|
|
|
{
|
|
|
|
|
|
using (new WriteLock(Locker))
|
|
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
foreach (var entry in GetDictionaryEntries()
|
|
|
|
|
|
.ToArray())
|
|
|
|
|
|
RemoveEntry((string) entry.Key);
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual void ClearCacheItem(string key)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (new WriteLock(Locker))
|
|
|
|
|
|
{
|
2014-05-22 09:36:08 +02:00
|
|
|
|
var cacheKey = GetCacheKey(key);
|
2014-05-27 12:16:41 +02:00
|
|
|
|
RemoveEntry(cacheKey);
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual void ClearCacheObjectTypes(string typeName)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (new WriteLock(Locker))
|
|
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
foreach (var entry in GetDictionaryEntries()
|
|
|
|
|
|
.Where(x =>
|
2013-09-18 12:27:38 +02:00
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
// entry.Value is Lazy<object> and not null, its value may be null
|
|
|
|
|
|
// remove null values as well, does not hurt
|
2014-06-17 18:42:00 +02:00
|
|
|
|
var value = GetSafeLazyValue((Lazy<object>) x.Value); // return exceptions as null
|
2014-05-27 12:16:41 +02:00
|
|
|
|
return value == null || value.GetType().ToString().InvariantEquals(typeName);
|
2013-09-18 12:27:38 +02:00
|
|
|
|
})
|
2014-05-27 12:16:41 +02:00
|
|
|
|
.ToArray())
|
|
|
|
|
|
RemoveEntry((string) entry.Key);
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2013-09-18 12:27:38 +02:00
|
|
|
|
|
|
|
|
|
|
public virtual void ClearCacheObjectTypes<T>()
|
|
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
var typeOfT = typeof(T);
|
2013-09-18 12:27:38 +02:00
|
|
|
|
using (new WriteLock(Locker))
|
|
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
foreach (var entry in GetDictionaryEntries()
|
|
|
|
|
|
.Where(x =>
|
2013-09-18 12:27:38 +02:00
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
// entry.Value is Lazy<object> and not null, its value may be null
|
|
|
|
|
|
// remove null values as well, does not hurt
|
|
|
|
|
|
// compare on exact type, don't use "is"
|
2014-06-17 18:42:00 +02:00
|
|
|
|
var value = GetSafeLazyValue((Lazy<object>)x.Value); // return exceptions as null
|
2014-05-27 12:16:41 +02:00
|
|
|
|
return value == null || value.GetType() == typeOfT;
|
2013-09-18 12:27:38 +02:00
|
|
|
|
})
|
2014-05-27 12:16:41 +02:00
|
|
|
|
.ToArray())
|
|
|
|
|
|
RemoveEntry((string) entry.Key);
|
2013-09-18 12:27:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual void ClearCacheObjectTypes<T>(Func<string, T, bool> predicate)
|
|
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
var typeOfT = typeof(T);
|
|
|
|
|
|
var plen = CacheItemPrefix.Length + 1;
|
2013-09-18 12:27:38 +02:00
|
|
|
|
using (new WriteLock(Locker))
|
|
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
foreach (var entry in GetDictionaryEntries()
|
|
|
|
|
|
.Where(x =>
|
2013-09-18 12:27:38 +02:00
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
// entry.Value is Lazy<object> and not null, its value may be null
|
|
|
|
|
|
// remove null values as well, does not hurt
|
|
|
|
|
|
// compare on exact type, don't use "is"
|
2014-06-17 18:42:00 +02:00
|
|
|
|
var value = GetSafeLazyValue((Lazy<object>)x.Value); // return exceptions as null
|
2014-05-27 12:16:41 +02:00
|
|
|
|
if (value == null) return true;
|
|
|
|
|
|
return value.GetType() == typeOfT
|
|
|
|
|
|
// run predicate on the 'public key' part only, ie without prefix
|
|
|
|
|
|
&& predicate(((string)x.Key).Substring(plen), (T)value);
|
|
|
|
|
|
}))
|
|
|
|
|
|
RemoveEntry((string) entry.Key);
|
2013-09-18 12:27:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-08-12 15:06:12 +02:00
|
|
|
|
public virtual void ClearCacheByKeySearch(string keyStartsWith)
|
|
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
var plen = CacheItemPrefix.Length + 1;
|
2014-05-22 09:36:08 +02:00
|
|
|
|
using (new WriteLock(Locker))
|
2013-08-12 15:06:12 +02:00
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
foreach (var entry in GetDictionaryEntries()
|
|
|
|
|
|
.Where(x => ((string)x.Key).Substring(plen).InvariantStartsWith(keyStartsWith))
|
|
|
|
|
|
.ToArray())
|
|
|
|
|
|
RemoveEntry((string) entry.Key);
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual void ClearCacheByKeyExpression(string regexString)
|
|
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
var plen = CacheItemPrefix.Length + 1;
|
2014-05-22 09:36:08 +02:00
|
|
|
|
using (new WriteLock(Locker))
|
2013-08-12 15:06:12 +02:00
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
foreach (var entry in GetDictionaryEntries()
|
|
|
|
|
|
.Where(x => Regex.IsMatch(((string)x.Key).Substring(plen), regexString))
|
|
|
|
|
|
.ToArray())
|
|
|
|
|
|
RemoveEntry((string) entry.Key);
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-05-27 12:16:41 +02:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Get
|
|
|
|
|
|
|
2013-08-12 15:06:12 +02:00
|
|
|
|
public virtual IEnumerable<object> GetCacheItemsByKeySearch(string keyStartsWith)
|
|
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
var plen = CacheItemPrefix.Length + 1;
|
2014-05-22 09:36:08 +02:00
|
|
|
|
using (new ReadLock(Locker))
|
|
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
return GetDictionaryEntries()
|
|
|
|
|
|
.Where(x => ((string)x.Key).Substring(plen).InvariantStartsWith(keyStartsWith))
|
2014-06-17 18:42:00 +02:00
|
|
|
|
.Select(x => GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
|
2014-05-27 12:16:41 +02:00
|
|
|
|
.Where(x => x != null) // backward compat, don't store null values in the cache
|
|
|
|
|
|
.ToList();
|
2014-05-22 09:36:08 +02:00
|
|
|
|
}
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-05-22 09:36:08 +02:00
|
|
|
|
public virtual IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
|
2014-04-17 18:10:42 +10:00
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
const string prefix = CacheItemPrefix + "-";
|
|
|
|
|
|
var plen = prefix.Length;
|
2014-05-22 09:36:08 +02:00
|
|
|
|
using (new ReadLock(Locker))
|
2014-04-17 18:10:42 +10:00
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
return GetDictionaryEntries()
|
|
|
|
|
|
.Where(x => Regex.IsMatch(((string)x.Key).Substring(plen), regexString))
|
2014-06-17 18:42:00 +02:00
|
|
|
|
.Select(x => GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
|
2014-05-27 12:16:41 +02:00
|
|
|
|
.Where(x => x != null) // backward compat, don't store null values in the cache
|
|
|
|
|
|
.ToList();
|
2014-05-22 09:36:08 +02:00
|
|
|
|
}
|
2014-04-17 18:10:42 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-08-12 15:06:12 +02:00
|
|
|
|
public virtual object GetCacheItem(string cacheKey)
|
|
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
cacheKey = GetCacheKey(cacheKey);
|
2014-05-22 09:36:08 +02:00
|
|
|
|
using (new ReadLock(Locker))
|
|
|
|
|
|
{
|
2014-05-27 12:16:41 +02:00
|
|
|
|
var result = GetEntry(cacheKey) as Lazy<object>; // null if key not found
|
2014-06-17 18:42:00 +02:00
|
|
|
|
return result == null ? null : GetSafeLazyValue(result); // return exceptions as null
|
2014-05-22 09:36:08 +02:00
|
|
|
|
}
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-05-27 12:16:41 +02:00
|
|
|
|
public abstract object GetCacheItem(string cacheKey, Func<object> getCacheItem);
|
2013-08-12 15:06:12 +02:00
|
|
|
|
|
2014-05-27 12:16:41 +02:00
|
|
|
|
#endregion
|
2013-08-12 15:06:12 +02:00
|
|
|
|
}
|
2013-08-08 19:46:58 +10:00
|
|
|
|
}
|