Ejemplo n.º 1
0
        private static TItem GetInternal <TItem, TSerialized>(string cacheKey, TimeSpan localExpiration, TimeSpan remoteExpiration,
                                                              string groupKey, Func <TItem> loader, Func <TItem, TSerialized> serialize, Func <TSerialized, TItem> deserialize)
            where TItem : class
            where TSerialized : class
        {
            ulong?groupGeneration      = null;
            ulong?groupGenerationCache = null;

            string itemGenerationKey = cacheKey + GenerationSuffix;

            var localCache       = LocalCache.Provider;
            var distributedCache = DistributedCache.Provider;

            // retrieves distributed cache group generation number lazily
            Func <ulong> getGroupGenerationValue = delegate()
            {
                if (groupGeneration != null)
                {
                    return(groupGeneration.Value);
                }

                groupGeneration = distributedCache.Get <ulong?>(groupKey);
                if (groupGeneration == null || groupGeneration == 0)
                {
                    groupGeneration = RandomGeneration();
                    distributedCache.Set(groupKey, groupGeneration.Value);
                }

                groupGenerationCache = groupGeneration.Value;
                // add to local cache, use 5 seconds from there
                LocalCache.Add(groupKey, groupGenerationCache, GenerationCacheExpiration);

                return(groupGeneration.Value);
            };

            // retrieves local cache group generation number lazily
            Func <ulong> getGroupGenerationCacheValue = delegate()
            {
                if (groupGenerationCache != null)
                {
                    return(groupGenerationCache.Value);
                }

                // check cached local value of group key
                // it expires in 5 seconds and read from server again
                groupGenerationCache = localCache.Get <object>(groupKey) as ulong?;

                // if its in local cache, return it
                if (groupGenerationCache != null)
                {
                    return(groupGenerationCache.Value);
                }

                return(getGroupGenerationValue());
            };



            // first check local cache, if item exists and not expired (group version = item version) return it
            var cachedObj = localCache.Get <object>(cacheKey);

            if (cachedObj != null)
            {
                // check local cache, if exists, compare version with group one
                var itemGenerationCache = localCache.Get <object>(itemGenerationKey) as ulong?;
                if (itemGenerationCache != null &&
                    itemGenerationCache == getGroupGenerationCacheValue())
                {
                    // local cached item is not expired yet

                    if (cachedObj == DBNull.Value)
                    {
                        return(null);
                    }

                    return((TItem)cachedObj);
                }

                // local cached item is expired, remove all information
                if (itemGenerationCache != null)
                {
                    localCache.Remove(itemGenerationKey);
                }

                localCache.Remove(cacheKey);

                cachedObj = null;
            }

            // if serializer is null, than this is a local store only item
            if (serialize != null)
            {
                // no item in local cache or expired, now check distributed cache
                var itemGeneration = distributedCache.Get <ulong?>(itemGenerationKey);

                // if item has version number in distributed cache and this is equal to group version
                if (itemGeneration != null &&
                    itemGeneration.Value == getGroupGenerationValue())
                {
                    // get item from distributed cache
                    var serialized = distributedCache.Get <TSerialized>(cacheKey);
                    // if item exists in distributed cache
                    if (serialized != null)
                    {
                        cachedObj = deserialize(serialized);
                        LocalCache.Add(cacheKey, (object)cachedObj ?? DBNull.Value, localExpiration);
                        LocalCache.Add(itemGenerationKey, getGroupGenerationValue(), localExpiration);
                        return((TItem)cachedObj);
                    }
                }
            }

            // couldn't find valid item in local or distributed cache, produce value by calling loader
            var item = loader();

            // add item and its version to cache
            LocalCache.Add(cacheKey, (object)item ?? DBNull.Value, localExpiration);
            LocalCache.Add(itemGenerationKey, getGroupGenerationValue(), localExpiration);

            if (serialize != null)
            {
                var serializedItem = serialize(item);

                // add item and generation to distributed cache
                if (remoteExpiration == TimeSpan.Zero)
                {
                    distributedCache.Set(cacheKey, serializedItem);
                    distributedCache.Set(itemGenerationKey, getGroupGenerationValue());
                }
                else
                {
                    distributedCache.Set(cacheKey, serializedItem, remoteExpiration);
                    distributedCache.Set(itemGenerationKey, getGroupGenerationValue(), remoteExpiration);
                }
            }

            return(item);
        }