/// <summary> /// Потокобезопасно берет объект из кэша, если его там нет, то вызывает функцию для получения данных /// и кладет результат в кэш /// </summary> /// <typeparam name="T">тип объектов в кэше</typeparam> /// <param name="provider">провайдер кэша</param> /// <param name="key">тэг, в общем случае представляет имя класса сервиса + имя метода + список параметров</param> /// <param name="tags">список зависимых контентов</param> /// <param name="expiration">время жизни в кэше</param> /// <param name="getData">функция для получения данных, если объектов кэше нет. нужно использовать анонимный делегат</param> /// <returns>закэшированне данные, если они присутствуют в кэше или результат выполнения функции</returns> public static T GetOrAdd <T>(this IVersionedCacheProvider provider, string key, string[] tags, TimeSpan expiration, Func <T> getData) { var supportCallbacks = _vProviderType.Value; object result = provider.Get(key, tags); object deprecatedResult = null; if (result == null) { object localLocker = _lockers.GetOrAdd(key, _ => new object()); bool lockTaken = false; try { Stopwatch sw = new Stopwatch(); sw.Start(); if (supportCallbacks) { // проверяем, что есть предыдущее значение deprecatedResult = provider.Get(VersionedCacheProvider3.CalculateDeprecatedKey(key)); if (deprecatedResult != null) { Monitor.TryEnter(localLocker, ref lockTaken); } else { Monitor.TryEnter(localLocker, TRYENTER_TIMEOUT_MS, ref lockTaken); } } else { Monitor.TryEnter(localLocker, TRYENTER_TIMEOUT_MS, ref lockTaken); } if (lockTaken) { result = provider.Get(key, tags); var time1 = sw.ElapsedMilliseconds; if (result == null) { DateTime startT = DateTime.Now; result = getData(); sw.Stop(); var time2 = sw.ElapsedMilliseconds; CheckPerformance(key, time1, time2); if (result != null) { provider.Add(result, key, tags, expiration); if (supportCallbacks && deprecatedResult != null) { provider.Invalidate(VersionedCacheProvider3.CalculateDeprecatedKey(key)); } } } } else { if (supportCallbacks && deprecatedResult != null) { return(Convert <T>(deprecatedResult)); } var time1 = sw.ElapsedMilliseconds; Logger.Log(() => string.Format("Долгое нахождение в ожидании обновления кэша {1} ms, ключ: {0} ", key, time1), EventLevel.Warning); result = getData(); sw.Stop(); var time2 = sw.ElapsedMilliseconds; CheckPerformance(key, time1, time2); if (result != null) { provider.Add(result, key, tags, expiration); if (supportCallbacks && deprecatedResult != null) { provider.Invalidate(VersionedCacheProvider3.CalculateDeprecatedKey(key)); } } } } finally { if (lockTaken) { Monitor.Exit(localLocker); } } } return(Convert <T>(result)); }
public ContentInvalidator(IVersionedCacheProvider cacheProvider) { _cacheProvider = cacheProvider; }