public void ScheduleRefresh(CacheEntry entry) { bool startTimer = false; lock (_entriesToRefresh) { bool isAutoRefresh = entry.CachePolicy == CachePolicy.AutoRefresh; int index = _entriesToRefresh.IndexOf(entry); if (index == -1 && isAutoRefresh) { _entriesToRefresh.Add(entry); } else if (index != -1 && !isAutoRefresh) { _entriesToRefresh.RemoveAt(index); } _entriesToRefresh.OrderBy(e => e.ExpirationTime); startTimer = _entriesToRefresh.Count > 0; } if (startTimer) { EnsureTimer(); } }
public CacheValueLoader(CacheEntry owningEntry) : base(owningEntry) { }
public LiveValueLoader(CacheEntry entry) : base(entry) { }
public ValueLoader(CacheEntry owningEntry) { CacheEntry = owningEntry; }
public EntryStats(CacheEntry entry) { _cacheEntry = entry; }
private CacheEntry Get <T>(LoadContext loadContext, Action <T> completed, Action <Exception> error, bool resetCallbacks) where T : new() { if (loadContext == null) { throw new ArgumentNullException("LoadContext required."); } object identity = loadContext.UniqueKey; CacheEntry value; lock (_objectCache) { if (_objectCache.ContainsKey(typeof(T)) && _objectCache[typeof(T)].TryGetValue(identity, out value)) { value.LoadContext = loadContext; if (resetCallbacks) { SetupCompletedCallback <T>(completed, error, value); } return(value); } } Type objectType = typeof(T); Action <CacheEntry> proxyCallback = cacheEntry => { var v = (T)cacheEntry.ValueInternal; foreach (var proxy in GetProxies <T>(cacheEntry.LoadContext)) { // copy the values over // ReflectionSerializer.UpdateObject(v, proxy.ProxyReference.Target, true, null); // fire the update notification // if (proxy.UpdateAction != null) { proxy.UpdateAction(); } } }; // create a new one. // value = new CacheEntry(loadContext, objectType, proxyCallback); value.NextCompletedAction.UnhandledError = OnUnhandledError; object loader = GetDataLoader(value); // How to create a new value. It's just a new. // value.CreateDefaultAction = () => { // if there is a proxy already registered, use it as the key value. // var proxy = GetProxies <T>(loadContext).FirstOrDefault(); if (proxy != null && proxy.ProxyReference != null && proxy.ProxyReference.IsAlive) { return(proxy.ProxyReference.Target); } var item = new T(); if (item is ILoadContextItem) { ((ILoadContextItem)item).LoadContext = value.LoadContext; } return(item); }; SetupCompletedCallback <T>(completed, error, value); // How to load a new value. // value.LoadAction = (lvl) => { if (loader == null) { throw new InvalidOperationException("Could not find loader for type: " + typeof(T).Name); } // get a loader and ask for a load request. // Debug.Assert(loader != null, "Failed to get loader for " + typeof(T).Name); var request = DataLoaderProxy.GetLoadRequest(loader, value.LoadContext, typeof(T)); if (request == null) { Debug.WriteLine("{0}: Aborting load for {1}, ID={2}, because {3}.GetLoadRequest returned null.", DateTime.Now, typeof(T).Name, value.LoadContext.Identity, loader.GetType().Name); return(false); } // fire off the load. // IsLoading = true; request.Execute( (result) => { if (result == null) { throw new ArgumentNullException("result", "Execute must return a LoadRequestResult value."); } if (result.Error == null) { lvl.OnLoadSuccess(result.Stream); } else { lvl.OnLoadFail(new LoadRequestFailedException(lvl.CacheEntry.ObjectType, value.LoadContext, result.Error)); } IsLoading = false; } ); return(true); }; // how to deserialize. value.DeserializeAction = (id, data, isOptimized) => { if (loader == null) { throw new InvalidOperationException("Could not find loader for type: " + typeof(T).Name); } // get the loader and ask for deserialization // object deserializedObject = null; if (isOptimized) { var idl = (IDataOptimizer)loader; if (idl == null) { throw new InvalidOperationException("Data is optimized but object does not implmenent IDataOptimizer"); } deserializedObject = idl.DeserializeOptimizedData(value.LoadContext, objectType, data); } else { deserializedObject = DataLoaderProxy.Deserialize(loader, value.LoadContext, objectType, data); } if (deserializedObject == null) { throw new InvalidOperationException(String.Format("Deserialize returned null for {0}, id='{1}'", objectType.Name, id)); } if (!objectType.IsInstanceOfType(deserializedObject)) { throw new InvalidOperationException(String.Format("Returned object is {0} when {1} was expected", deserializedObject.GetType().Name, objectType.Name)); } return(deserializedObject); }; // if this thing knows how to optimize, hook that up. // if (loader is IDataOptimizer) { value.SerializeOptimizedDataAction = (obj, stream) => { var idl = (IDataOptimizer)loader; return(idl.SerializeOptimizedData(obj, stream)); }; } // finally push the value into the cache. lock (_objectCache) { if (!_objectCache.ContainsKey(objectType)) { Dictionary <object, CacheEntry> typeDictionary = new Dictionary <object, CacheEntry>(); _objectCache[typeof(T)] = typeDictionary; } _objectCache[typeof(T)][identity] = value; } return(value); }
/// <summary> /// Figure out what dataloader to use for the entry type. /// </summary> /// <param name="entry"></param> /// <returns></returns> private object GetDataLoader(CacheEntry entry) { object loader; var objectType = entry.ObjectType; lock (_loaders) { if (_loaders.TryGetValue(objectType, out loader)) { return(loader); } } var attrs = objectType.GetCustomAttributes(typeof(DataLoaderAttribute), true); if (attrs.Length > 0) { DataLoaderAttribute dla = (DataLoaderAttribute)attrs[0]; if (dla.DataLoaderType != null) { loader = Activator.CreateInstance(dla.DataLoaderType); } } else { // GetNestedTypes returns the nested types defined on the current // type only, so it will not get loaders defined on super classes. // So we just walk through the types until we find one or hit System.Object. // for (Type modelType = objectType; loader == null && modelType != typeof(object); modelType = modelType.BaseType) { // see if we already have a loader at this level // if (_loaders.TryGetValue(modelType, out loader) && loader != null) { break; } var loaders = from nt in modelType.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic) where nt.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDataLoader <>)) select nt; Type loaderType = loaders.FirstOrDefault(); if (loaderType != null) { loader = Activator.CreateInstance(loaderType); // if we're walking base types, save this value so that the subsequent requests will get it. // if (loader != null && modelType != objectType) { _loaders[modelType] = loader; } } } } lock (_loaders) { if (loader != null) { _loaders[objectType] = loader; return(loader); } } throw new InvalidOperationException(String.Format("DataLoader not specified for type {0}. All DataManager-loaded types must implement a data loader by one of the following methods:\r\n\r\n1. Specify a IDataLoader-implementing type on the class with the DataLoaderAttribute.\r\n2. Create a public nested type that implements IDataLoader.", objectType.Name)); }
/// <summary> /// Setup the callbacks to fire upon completiion of the next load operation. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="completed"></param> /// <param name="error"></param> /// <param name="value"></param> private void SetupCompletedCallback <T>(Action <T> completed, Action <Exception> error, CacheEntry value) where T : new() { value.NextCompletedAction.Subscribe(completed, error); #if DEBUG value.LastLoadStackTrace = new StackTrace(); #endif }