public Cache(Func <T, R> function, Func <IMemoizationCacheEntryMetrics, TMetric> ranker, int maxCapacity, bool descending, double ageThreshold, bool cacheError, IStopwatchFactory stopwatchFactory) { _function = args => { var weakArgs = WeakReferenceExtensions.Create(args); var invokeDuration = default(TimeSpan); #if DEBUG Interlocked.Increment(ref _invocationCount); #endif Trim(); var res = default(IMetricsCacheEntry <WeakReference <T>, R>); try { var swInvokeStart = _stopwatch.ElapsedTicks; var value = function(args); invokeDuration = new TimeSpan(_stopwatch.ElapsedTicks - swInvokeStart); res = new MetricsValueCacheEntry <WeakReference <T>, R>(weakArgs, value); } catch (Exception ex) when(_cacheError) { res = new MetricsErrorCacheEntry <WeakReference <T>, R>(weakArgs, ex); } res.CreationTime = new TimeSpan(_stopwatch.ElapsedTicks); res.InvokeDuration = invokeDuration; _lock.EnterWriteLock(); try { _entries.Add(res); } finally { _lock.ExitWriteLock(); } return(res); }; _cache = new WeakCacheDictionary <T, IMetricsCacheEntry <WeakReference <T>, R> >(); _lock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); _entries = new HashSet <IMetricsCacheEntry <WeakReference <T>, R> >(); _stopwatch = stopwatchFactory.StartNew(); // // Exclude newest items which have statically irrelevant data, so they get a chance to become relevant. // var candidates = _entries.OrderBy(e => _stopwatch.ElapsedTicks - e.CreationTime.Ticks).Take(Math.Max(1, (int)(maxCapacity * ageThreshold))); _ranker = descending ? candidates.OrderByDescending(e => ranker(e)) : candidates.OrderBy(e => ranker(e)); _maxCapacity = maxCapacity; _cacheError = cacheError; }
public Cache(Func <T, R> function, Func <IMemoizationCacheEntryMetrics, TMetric> ranker, int maxCapacity, bool descending, double ageThreshold, IEqualityComparer <T> comparer, bool cacheError, IStopwatchFactory stopwatchFactory) { _function = args => { var invokeDuration = default(TimeSpan); #if DEBUG _invocationCount++; #endif Trim(); var res = default(IMetricsCacheEntry <T, R>); try { var swInvokeStart = _stopwatch.ElapsedTicks; var value = function(args); invokeDuration = new TimeSpan(_stopwatch.ElapsedTicks - swInvokeStart); res = new MetricsValueCacheEntry <T, R>(args, value); } catch (Exception ex) when(_cacheError) { res = new MetricsErrorCacheEntry <T, R>(args, ex); } res.CreationTime = new TimeSpan(_stopwatch.ElapsedTicks); res.InvokeDuration = invokeDuration; return(res); }; _cache = new CacheDictionary <T, IMetricsCacheEntry <T, R> >(comparer); _stopwatch = stopwatchFactory.StartNew(); // // Exclude newest items which have statically irrelevant data, so they get a chance to become relevant. // var candidates = _cache.Values.OrderBy(e => _stopwatch.ElapsedTicks - e.CreationTime.Ticks).Take(Math.Max(1, (int)(maxCapacity * ageThreshold))); _ranker = descending ? candidates.OrderByDescending(e => ranker(e)) : candidates.OrderBy(e => ranker(e)); _maxCapacity = maxCapacity; _cacheError = cacheError; }