public async Task <CachedObject <TResult> > GetAsync <TResult>(ProxiedMethodInvocation <T, TResult> proxiedMethodInvocation, CachePolicy cachePolicy)
        {
            return(await Task.Factory.StartNew(() =>
            {
                var hash = proxiedMethodInvocation.GetHashString();
                DictionaryCacheItem cachedObject;
                if (_cache.TryGetValue(hash, out cachedObject))
                {
                    if (cachedObject.ThrownException != null && cachedObject.Created.AddSeconds(cachePolicy.ExceptionCacheDuration) > DateTime.Now)
                    {
                        return new CachedObject <TResult>(CachedObjectState.Exception, cachedObject.ThrownException);
                    }
                    else if (cachedObject.ThrownException != null)
                    {
                        return new CachedObject <TResult>(CachedObjectState.None, null);
                    }

                    if (cachedObject.AbsoluteDuration.TotalSeconds > 0 && cachedObject.Created + cachedObject.AbsoluteDuration < DateTime.Now)
                    {
                        return new CachedObject <TResult>(CachedObjectState.None, null);
                    }

                    return new CachedObject <TResult>(cachedObject.IsExpired ? CachedObjectState.Stale : CachedObjectState.Fresh, (TResult)cachedObject.Object);
                }
                return CachedObject <TResult> .Empty();
            }));
        }
        public async Task StoreExceptionAsync <TResult>(ProxiedMethodInvocation <T, TResult> proxiedMethodInvocation, CachePolicy cachePolicy, Exception e)
        {
            await Task.Factory.StartNew(() =>
            {
                var hash             = proxiedMethodInvocation.GetHashString();
                var duration         = TimeSpan.FromSeconds(cachePolicy.CacheDuration);
                var absoluteDuration = TimeSpan.FromSeconds(cachePolicy.MaxAge);

                _cache[hash] = new DictionaryCacheItem(e, duration, absoluteDuration);
            });
        }
예제 #3
0
        public async Task <CachedObject <TResult> > GetAsync <TResult>(ProxiedMethodInvocation <T, TResult> proxiedMethodInvocation, CachePolicy cachePolicy)
        {
            var key           = proxiedMethodInvocation.GetHashString(_hashScramble);
            var memcachedItem = await _memcachedCluster.Get(key);

            if (memcachedItem != null)
            {
                MemcachedObject <TResult> cacheItem;
                using (var zipStream = new GZipStream(memcachedItem.Data, CompressionMode.Decompress))
                {
                    using (var streamReader = new StreamReader(zipStream))
                    {
                        var textReader = new JsonTextReader(streamReader);
                        try
                        {
                            cacheItem = _serializer.Deserialize <MemcachedObject <TResult> >(textReader);
                        }
                        catch (JsonSerializationException)
                        {
                            //This exception occurs if whatever is in memcached is impossible to deserialize. It's a tricky case, but we'll have to report back that nothing is in there.
                            return(new CachedObject <TResult>(CachedObjectState.None, default(TResult)));
                        }
                    }
                }

                if (cacheItem == null)
                {
                    return(new CachedObject <TResult>(CachedObjectState.None, default(TResult)));
                }

                if (cacheItem.IsException && cacheItem.Created.AddSeconds(cachePolicy.ExceptionCacheDuration) > DateTime.Now)
                {
                    return(new CachedObject <TResult>(CachedObjectState.Exception, cacheItem.Exception));
                }
                else if (cacheItem.IsException)
                {
                    return(new CachedObject <TResult>(CachedObjectState.None, default(TResult)));
                }

                var fresh = cacheItem.Created.AddSeconds(cachePolicy.CacheDuration) > DateTime.Now;
                var state = fresh ? CachedObjectState.Fresh : CachedObjectState.Stale;

                if (cachePolicy.DiscardStale && state == CachedObjectState.Stale)
                {
                    return(new CachedObject <TResult>(CachedObjectState.None, default(TResult)));
                }

                return(new CachedObject <TResult>(state, cacheItem.Object));
            }

            return(new CachedObject <TResult>(CachedObjectState.None, default(TResult)));
        }
        public static byte[] GetHashBytes <T, TResult>(this ProxiedMethodInvocation <T, TResult> invocation, string scrambleString = null) where T : class
        {
            var sb = new StringBuilder();

            sb.Append(typeof(T).FullName);
            sb.Append(" - ");
            sb.Append(invocation.Method);
            sb.Append(" - ");
            sb.AddParameterRepresentations(invocation.Parameters);
            if (!string.IsNullOrEmpty(scrambleString))
            {
                sb.Append(" - ");
                sb.Append(scrambleString);
            }

            var bytes         = Encoding.UTF8.GetBytes(sb.ToString());
            var hashAlgorithm = new SHA256Managed();
            var hash          = hashAlgorithm.ComputeHash(bytes);

            return(hash);
        }
예제 #5
0
        public async Task StoreAsync <TResult>(ProxiedMethodInvocation <T, TResult> proxiedMethodInvocation, CachePolicy cachePolicy, TResult data)
        {
            var key          = proxiedMethodInvocation.GetHashString(_hashScramble);
            var cachedObject = new MemcachedObject <TResult>()
            {
                Created = DateTime.Now,
                Object  = data
            };

            var bytes = SerializeAndZip(cachedObject);

            if (cachePolicy.MaxAge > 0)
            {
                await _memcachedCluster.Set(key, bytes, new MemcachedStorageOptions()
                {
                    ExpirationTime = TimeSpan.FromSeconds(cachePolicy.MaxAge)
                });
            }
            else
            {
                await _memcachedCluster.Set(key, bytes);
            }
        }
예제 #6
0
        public async Task <TResult> LookupAsync <TResult>(ProxiedMethodInvocation <T, TResult> methodInvocation)
        {
            var cachePolicy = _cachePolicyProvider.GetPolicy(methodInvocation.Method, methodInvocation.Parameters);

            if (cachePolicy == null || cachePolicy.CacheDuration <= 0)
            {
                return(await methodInvocation.InvokeAsync(_implementation));
            }

            var cachedItem = await _cache.GetAsync(methodInvocation, cachePolicy) ?? new CachedObject <TResult>(CachedObjectState.None, null);

            if (cachedItem.State == CachedObjectState.Fresh)
            {
                return(cachedItem.Object);
            }

            if (cachedItem.State == CachedObjectState.Exception)
            {
                throw cachedItem.ThrownException;
            }

            var            requestKey = new RequestKey(methodInvocation.Method, methodInvocation.Parameters);
            Task <TResult> awaitableTask;

            if (_taskSyncronizer.TryGetAwaitable(requestKey, () => methodInvocation.InvokeAsync(_implementation), out awaitableTask))
            {
                if (cachedItem.State == CachedObjectState.Stale)
                {
                    return(cachedItem.Object);
                }

                return(await awaitableTask);
            }

            if (cachedItem.State == CachedObjectState.Stale)
            {
                try
                {
                    Exception thrownException = null;
                    try
                    {
                        var data = await awaitableTask;
                        await _cache.StoreAsync(methodInvocation, cachePolicy, data);

                        return(data);
                    }
                    catch (Exception e)
                    {
                        thrownException = e;
                    }

                    if (cachePolicy.BubbleExceptions)
                    {
                        await _cache.StoreExceptionAsync(methodInvocation, cachePolicy, thrownException);

                        throw thrownException;
                    }
                    else
                    {
                        await _cache.StoreAsync(methodInvocation, cachePolicy, cachedItem.Object);

                        return(cachedItem.Object);
                    }
                }
                finally
                {
                    _taskSyncronizer.Release(requestKey);
                }
            }

            try
            {
                Exception thrownException = null;
                try
                {
                    var data = await awaitableTask;
                    await _cache.StoreAsync(methodInvocation, cachePolicy, data);

                    return(data);
                }
                catch (Exception e)
                {
                    thrownException = e;
                }

                await _cache.StoreExceptionAsync(methodInvocation, cachePolicy, thrownException);

                throw thrownException;
            }
            finally
            {
                _taskSyncronizer.Release(requestKey);
            }
        }
 public static string GetHashString <T, TResult>(this ProxiedMethodInvocation <T, TResult> invocation, string scrambleString = null) where T : class
 {
     return(Convert.ToBase64String(GetHashBytes(invocation, scrambleString)));
 }
예제 #8
0
        public TResult Lookup <TResult>(ProxiedMethodInvocation <T, TResult> methodInvocation)
        {
            var cachePolicy = _cachePolicyProvider.GetPolicy(methodInvocation.Method, methodInvocation.Parameters);

            if (cachePolicy == null || cachePolicy.CacheDuration == 0)
            {
                return(methodInvocation.Invoke(_implementation));
            }

            var cachedItem = AsyncContext.Run(() => _cache.GetAsync(methodInvocation, cachePolicy)) ?? new CachedObject <TResult>(CachedObjectState.None, null);

            if (cachedItem.State == CachedObjectState.Fresh)
            {
                return(cachedItem.Object);
            }

            if (cachedItem.State == CachedObjectState.Exception)
            {
                throw cachedItem.ThrownException;
            }

            var requestKey = new RequestKey(methodInvocation.Method, methodInvocation.Parameters);
            RequestWaitHandle <TResult> waitHandle;

            if (_syncronizer.ShouldWaitForHandle(requestKey, out waitHandle))
            {
                if (cachedItem.State == CachedObjectState.Stale)
                {
                    return(cachedItem.Object);
                }

                return(waitHandle.WaitForResult());
            }

            if (cachedItem.State == CachedObjectState.Stale)
            {
                Func <TResult> loader = () => methodInvocation.Invoke(_implementation);

                loader.BeginInvoke(callback =>
                {
                    Exception asyncRequestThrownException = null;
                    var asyncResult = default(TResult);

                    try
                    {
                        asyncResult = loader.EndInvoke(callback);
                        AsyncContext.Run(() => _cache.StoreAsync(methodInvocation, cachePolicy, asyncResult));
                    }
                    catch (Exception e)
                    {
                        if (cachePolicy.BubbleExceptions)
                        {
                            AsyncContext.Run(() => _cache.StoreExceptionAsync(methodInvocation, cachePolicy, e));
                            asyncRequestThrownException = e;
                        }
                        else
                        {
                            asyncResult = cachedItem.Object;
                            AsyncContext.Run(() => _cache.StoreAsync(methodInvocation, cachePolicy, asyncResult));
                        }
                    }
                    finally
                    {
                        if (asyncRequestThrownException != null)
                        {
                            _syncronizer.ReleaseWithException <TResult>(requestKey, asyncRequestThrownException);
                        }
                        else
                        {
                            _syncronizer.Release(requestKey, asyncResult);
                        }
                    }
                }, null);

                return(cachedItem.Object);
            }

            //At this point nothing is in the cache.
            var       realInstanceResult = default(TResult);
            Exception thrownException    = null;

            try
            {
                realInstanceResult = methodInvocation.Invoke(_implementation);
                AsyncContext.Run(() => _cache.StoreAsync(methodInvocation, cachePolicy, realInstanceResult));
            }
            catch (Exception e)
            {
                thrownException = e;
                AsyncContext.Run(() => _cache.StoreExceptionAsync(methodInvocation, cachePolicy, thrownException));
                throw;
            }
            finally
            {
                if (thrownException != null)
                {
                    _syncronizer.ReleaseWithException <TResult>(requestKey, thrownException);
                }
                else
                {
                    _syncronizer.Release(requestKey, realInstanceResult);
                }
            }

            return(realInstanceResult);
        }
예제 #9
0
 public CachePolicy GetPolicy <TResult>(ProxiedMethodInvocation <T, TResult> invocation)
 {
     return(GetPolicy(invocation.Method, invocation.Parameters));
 }
 public TResult Handle <TResult>(ProxiedMethodInvocation <T, TResult> methodInvocation)
 {
     return(_syncLookupHandler.Lookup(methodInvocation));
 }
 public async Task <TResult> HandleAsync <TResult>(ProxiedMethodInvocation <T, TResult> methodInvocation)
 {
     return(await _asyncLookupHandler.LookupAsync(methodInvocation));
 }