Пример #1
0
        /// <summary>
        /// Core cache proc method [low level].
        /// Will try to find result in cache based on key, else will call the func and store result in cache attached to the key.
        /// </summary>
        /// <typeparam name="R">Function result type</typeparam>
        /// <param name="Key">Key to asssociate with the result</param>
        /// <param name="Factory">Function to produce the result</param>
        /// <returns>Function call result ether actual or cached</returns>
        protected R GetOrMakeWithKey <R>(Object Key, Func <R> Factory)
        {
            Interlocked.Increment(ref CacheStatUseCount);

            CacheItem          CacheEntry;
            FuncCallResult <R> CachedResult = null;

            lock (Cache)
            {
                if (Cache.TryGetValue(Key, out CacheEntry))
                {
                    CachedResult = CacheEntry.CallResult as FuncCallResult <R>;
                    if (CachedResult != null)
                    {
                        // Found and type is valid
                        if (isExpiried(CacheEntry))
                        {
                            CachedResult = null;
                            Cache.Remove(Key); // expiried entry
                            CacheEntry = null;
                        }
                    }
                    else
                    {
                        Cache.Remove(Key); // invalid entry (bug trap)
                        CacheEntry = null;
                    }
                }
                else
                {
                    CacheEntry = null;
                }
            }

            if (CachedResult == null)
            {
                // not found in cache

                CachedResult = FuncCall.Call(Factory); // That may take long time and we are not locked

                var Now = GetLongTickCount();

                CacheEntry = new CacheItem
                {
                    MakeTimestamp       = Now,
                    LastAccessTimestamp = Now,
                    CallResult          = CachedResult
                };

                CacheStatLastAccessTimestamp = Now;

                lock (Cache)
                {
                    try
                    {
                        Cache.Add(Key, CacheEntry);
                    }
                    catch
                    {
                        // Someone already added result (earlier)
                        try
                        {
                            // Refresh
                            Cache.Remove(Key);
                            Cache.Add(Key, CacheEntry);
                        }
                        catch
                        {
                            // Failed to remove/add?
                            // This should not be a case since we are in lock
                            throw;
                        }
                    }
                }
            }
            else
            {
                // Found in cache
                var Now = GetLongTickCount();
                Interlocked.Increment(ref CacheEntry.HitCount);
                CacheEntry.LastAccessTimestamp = Now;

                Interlocked.Increment(ref CacheStatHitCount);
                CacheStatLastAccessTimestamp = Now;
            }

            if (CachedResult.Exception != null)
            {
                throw CachedResult.Exception; // rethrow
            }

            return(CachedResult.Result);
        }