/// <summary> /// Returns the time that the key was added to the cache, or returns /// null if the key isn't in the cache. /// </summary> /// <param name="key">The key to return the date for.</param> /// <returns>The date the key was created on.</returns> public static IObservable <DateTimeOffset?> GetObjectCreatedAt <T>(this IBlobCache This, string key) { var objCache = This as IObjectBlobCache; if (objCache != null) { return(This.GetCreatedAt(key)); } return(This.GetCreatedAt(key)); }
/// <summary> /// This is the non-generic analog of JsonSerializationMixin.GetAndFetchLatest[1] /// We shouldn't make modifications to this that alter its behavior from the generic /// version. By having this we can keep our two GetAndRefresh methods extremely /// similar and thus trust that what works in one will work in the other. /// /// 1. https://github.com/akavache/Akavache/blob/1b19bb56d/Akavache/Portable/JsonSerializationMixin.cs#L202-L236 /// </summary> static IObservable <byte[]> GetAndFetchLatestBytes( this IBlobCache blobCache, string key, Func <IObservable <byte[]> > fetchFunc, Func <DateTimeOffset, bool> fetchPredicate = null, DateTimeOffset?absoluteExpiration = null) { var fetch = Observable.Defer(() => blobCache.GetCreatedAt(key)) .Select(x => fetchPredicate == null || x == null || fetchPredicate(x.Value)) .Where(predicateIsTrue => predicateIsTrue) .SelectMany(_ => { return(fetchFunc() .SelectMany(x => blobCache.Invalidate(key).Select(__ => x)) .SelectMany(x => blobCache.Insert(key, x, absoluteExpiration).Select(__ => x))); }); var result = blobCache.Get(key).Select(x => Tuple.Create(x, true)) .Catch(Observable.Return(new Tuple <byte[], bool>(null, false))); return(result .SelectMany(x => x.Item2 ? Observable.Return(x.Item1) : Observable.Empty <byte[]>()) .Concat(fetch) .Replay() .RefCount()); }
/// <summary> /// This method attempts to returned a cached value, while /// simultaneously calling a Func to return the latest value. When the /// latest data comes back, it replaces what was previously in the /// cache. /// /// This method is best suited for loading dynamic data from the /// Internet, while still showing the user earlier data. /// /// This method returns an IObservable that may return *two* results /// (first the cached data, then the latest data). Therefore, it's /// important for UI applications that in your Subscribe method, you /// write the code to merge the second result when it comes in. /// </summary> /// <param name="key">The key to store the returned result under.</param> /// <param name="fetchFunc"></param> /// <param name="fetchPredicate">An optional Func to determine whether /// the updated item should be fetched. If the cached version isn't found, /// this parameter is ignored and the item is always fetched.</param> /// <param name="absoluteExpiration">An optional expiration date.</param> /// <returns>An Observable stream containing either one or two /// results (possibly a cached version, then the latest version)</returns> public static IObservable <T> GetAndFetchLatest <T>(this IBlobCache This, string key, Func <IObservable <T> > fetchFunc, Func <DateTimeOffset, bool> fetchPredicate = null, DateTimeOffset?absoluteExpiration = null) { bool foundItemInCache; var fail = Observable.Defer(() => This.GetCreatedAt(key)) .Select(x => fetchPredicate != null && x != null ? fetchPredicate(x.Value) : true) .Where(x => x != false) .SelectMany(_ => fetchFunc()) .Finally(() => This.Invalidate(key)) .Do(x => This.InsertObject(key, x, absoluteExpiration)); var result = This.GetObjectAsync <T>(key).Select(x => new Tuple <T, bool>(x, true)) .Catch(Observable.Return(new Tuple <T, bool>(default(T), false))); return(result.SelectMany(x => { foundItemInCache = x.Item2; return x.Item2 ? Observable.Return(x.Item1) : Observable.Empty <T>(); }).Concat(fail).Multicast(new ReplaySubject <T>()).RefCount()); }
public bool ContainsKey(string key) { var result = blobCache.GetCreatedAt(key).Wait(); // FIX: Temporarily logging this, as I suspect it of always returning true Log.Verbose(TAG, $"ContainsKey: {key} = {result.HasValue}"); return(result.HasValue); }
/// <summary> /// Returns the time that the key was added to the cache, or returns /// null if the key isn't in the cache. /// </summary> /// <typeparam name="T">The type of item to get.</typeparam> /// <param name="blobCache">The cache to get the item.</param> /// <param name="key">The key to return the date for.</param> /// <returns>The date the key was created on.</returns> public static IObservable <DateTimeOffset?> GetObjectCreatedAt <T>(this IBlobCache blobCache, string key) { if (blobCache is IObjectBlobCache objCache) { return(objCache.GetObjectCreatedAt <T>(key)); } return(blobCache.GetCreatedAt(GetTypePrefixedKey(key, typeof(T)))); }
/// <summary> /// Gets a dictionary filled with the specified keys with their corresponding created <see cref="DateTimeOffset"/> /// if it's available. /// </summary> /// <param name="blobCache">The blob cache to extract the values from.</param> /// <param name="keys">The keys to get the values for.</param> /// <returns>A observable with the specified values.</returns> public static IObservable <IDictionary <string, DateTimeOffset?> > GetCreatedAt(this IBlobCache blobCache, IEnumerable <string> keys) { if (blobCache is IBulkBlobCache bulkCache) { return(bulkCache.GetCreatedAt(keys)); } return(keys.ToObservable() .SelectMany(x => blobCache.GetCreatedAt(x).Select(y => new { Key = x, Value = y })) .ToDictionary(k => k.Key, v => v.Value)); }
/// <summary> /// Returns the time that the key was added to the cache, or returns /// null if the key isn't in the cache. /// </summary> /// <param name="key">The key to return the date for.</param> /// <returns>The date the key was created on.</returns> public static IObservable <DateTimeOffset?> GetObjectCreatedAt <T>(this IBlobCache This, string key) { var objCache = This as IObjectBlobCache; if (objCache != null) { return(objCache.GetObjectCreatedAt <T>(key)); } return(This.GetCreatedAt(GetTypePrefixedKey(key, typeof(T)))); }
/// <summary> /// Returns the time that the key was added to the cache, or returns /// null if the key isn't in the cache. /// </summary> /// <typeparam name="T">The type of item to get.</typeparam> /// <param name="blobCache">The cache to get the item.</param> /// <param name="key">The key to return the date for.</param> /// <returns>The date the key was created on.</returns> public static IObservable <DateTimeOffset?> GetObjectCreatedAt <T>(this IBlobCache blobCache, string key) { if (blobCache is null) { throw new ArgumentNullException(nameof(blobCache)); } if (blobCache is IObjectBlobCache objCache) { return(objCache.GetObjectCreatedAt <T>(key)); } return(blobCache.GetCreatedAt(GetTypePrefixedKey(key, typeof(T)))); }
static IObservable <Unit> VacuumIfNecessary(IBlobCache blobCache, bool force = false) { const string key = "__Vacuumed"; var vauumInterval = TimeSpan.FromDays(30); return(Observable.Defer(() => blobCache.GetCreatedAt(key)) .Where(lastVacuum => force || !lastVacuum.HasValue || blobCache.Scheduler.Now - lastVacuum.Value > vauumInterval) .SelectMany(Observable.Defer(blobCache.Vacuum)) .SelectMany(Observable.Defer(() => blobCache.Insert(key, new byte[] { 1 }))) .Catch <Unit, Exception>(ex => { log.Error("Could not vacuum image cache", ex); return Observable.Return(Unit.Default); }) .AsCompletion()); }
public IObservable <DateTimeOffset?> GetCreatedAt(string key) { return(_inner.GetCreatedAt(key)); }
public static bool NeedsMigration(IBlobCache blobCache) { return(blobCache.GetCreatedAt(MigratedKey).Wait() == null); }
public static bool NeedsMigration(IBlobCache blobCache) { return blobCache.GetCreatedAt(MigratedKey).Wait() == null; }