Example #1
0
        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();
            }
        }
Example #2
0
 public CacheValueLoader(CacheEntry owningEntry)
     : base(owningEntry)
 {
 }
Example #3
0
 public LiveValueLoader(CacheEntry entry)
     : base(entry)
 {
 }
Example #4
0
 public ValueLoader(CacheEntry owningEntry)
 {
     CacheEntry = owningEntry;
 }
Example #5
0
 public EntryStats(CacheEntry entry)
 {
     _cacheEntry = entry;
 }
Example #6
0
 public EntryStats(CacheEntry entry)
 {
     _cacheEntry = entry;
 }
Example #7
0
        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);
        }
Example #8
0
        /// <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));
        }
Example #9
0
        /// <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
        }