public async Task MemoizeAsync_CallAfterRefreshTime_RefreshOnBackground() { TimeSpan refreshTime = TimeSpan.FromMinutes(1); var refreshTask = new TaskCompletionSource <Thing>(); var args = new object[] { "someString" }; string firstValue = "first Value"; string secondValue = "second Value"; var dataSource = CreateDataSource(firstValue, refreshTask); IMemoizer memoizer = CreateMemoizer(CreateCache()); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, args, GetPolicy())).Id.ShouldBe(firstValue); // fake that refreshTime has passed TimeFake.UtcNow += refreshTime; // Refresh task hasn't finished, should get old value (5) (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, args, GetPolicy())).Id.ShouldBe(firstValue); // value is not refreshed yet. it is running on background // Complete refresh task and verify new value refreshTask.SetResult(new Thing { Id = secondValue, Name = "seven" }); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, args, GetPolicy())).Id.ShouldBe(secondValue); // new value is expected now }
public async Task MemoizeAsync_TwoCalls_RespectsCachingPolicy() { var dataSource = CreateDataSource(5, 7); IMemoizer memoizer = CreateMemoizer(CreateCache()); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, new object[] { "someString" }, GetPolicy(0.05))).Id.ShouldBe(5); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, new object[] { "someString" }, GetPolicy())).Id.ShouldBe(5); await Task.Delay(100); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, new object[] { "someString" }, GetPolicy())).Id.ShouldBe(7); dataSource.Received(2).ThingifyTaskThing("someString"); }
public async Task MemoizeAsync_MultipleIdenticalCallsBeforeFirstCompletes_TeamsWithFirstCall() { var dataSource = CreateDataSource(); dataSource.ThingifyTaskInt("someString").Returns(async i => { await Task.Delay(100); return(1); }, async i => 2); IMemoizer memoizer = CreateMemoizer(CreateCache()); var task1 = (Task <int>)memoizer.Memoize(dataSource, ThingifyTaskInt, new object[] { "someString" }, GetPolicy()); var task2 = (Task <int>)memoizer.Memoize(dataSource, ThingifyTaskInt, new object[] { "someString" }, GetPolicy()); var task3 = (Task <int>)memoizer.Memoize(dataSource, ThingifyTaskInt, new object[] { "someString" }, GetPolicy()); await Task.WhenAll(task1, task2, task3); dataSource.Received(1).ThingifyTaskInt("someString"); }
public async Task MemoizeAsync_TwoCalls_RespectsCachingPolicy() { string firstValue = "first Value"; string secondValue = "second Value"; var dataSource = CreateDataSource(firstValue, secondValue); IMemoizer memoizer = CreateMemoizer(CreateCache()); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, new object[] { "someString" }, GetPolicy(1))).Id.ShouldBe(firstValue); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, new object[] { "someString" }, GetPolicy(1))).Id.ShouldBe(firstValue); await Task.Delay(TimeSpan.FromSeconds(2)); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, new object[] { "someString" }, GetPolicy(1))).Id.ShouldBe(secondValue); dataSource.Received(2).ThingifyTaskThing("someString"); }
/// <summary> /// Instantiates the expression Bonsai serializer. /// </summary> /// <param name="version">Version of Bonsai to use.</param> /// <param name="liftMemoizer">The function memoizer to use for converting types to object serializers.</param> /// <param name="reduceMemoizer">The function memoizer to use for converting types to object deserializers.</param> public BonsaiExpressionSerializer(Version version, IMemoizer liftMemoizer, IMemoizer reduceMemoizer) { _version = version; _serializeConstant = liftMemoizer?.Memoize <Func <Type, Func <object, Json.Expression> > >(GetConstantSerializer); _deserializeConstant = reduceMemoizer?.Memoize <Func <Type, Func <Json.Expression, object> > >(GetConstantDeserializer); }
public void MemoizeAsync_MultipleIdenticalCallsBeforeFirstFails_TeamsWithFirstCall() { var dataSource = Substitute.For <IThingFrobber>(); dataSource.ThingifyTaskInt("someString").Returns <Task <int> >(async i => { await Task.Delay(100); throw new InvalidOperationException(); }, async i => 2); IMemoizer memoizer = CreateMemoizer(CreateCache()); var task1 = (Task <int>)memoizer.Memoize(dataSource, ThingifyTaskInt, new object[] { "someString" }, GetPolicy()); var task2 = (Task <int>)memoizer.Memoize(dataSource, ThingifyTaskInt, new object[] { "someString" }, GetPolicy()); var task3 = (Task <int>)memoizer.Memoize(dataSource, ThingifyTaskInt, new object[] { "someString" }, GetPolicy()); task1.ShouldThrow <InvalidOperationException>(); task2.ShouldThrow <InvalidOperationException>(); task3.ShouldThrow <InvalidOperationException>(); dataSource.Received(1).ThingifyTaskInt("someString"); }
public async Task MemoizeAsync_CallsWithDifferentParams_UsesSeparateCacheSlots() { var dataSource = CreateDataSource(5); dataSource.ThingifyTaskThing("otherString").Returns(Task.FromResult(new Thing { Id = 7 })); IMemoizer memoizer = CreateMemoizer(CreateCache()); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, new object[] { "someString" }, GetPolicy())).Id.ShouldBe(5); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, new object[] { "otherString" }, GetPolicy())).Id.ShouldBe(7); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, new object[] { "someString" }, GetPolicy())).Id.ShouldBe(5); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, new object[] { "otherString" }, GetPolicy())).Id.ShouldBe(7); dataSource.Received(1).ThingifyTaskThing("someString"); dataSource.Received(1).ThingifyTaskThing("otherString"); }
/// <summary> /// Creates a new evaluator factory using the specified <paramref name="memoizer"/> to cache the /// compiled delegates created by <see cref="ShouldCache(MemberInfo)"/>. Note that the member objects /// and the evaluator delegates can be held alive by the cache created through the memoizer. See /// other constructor overloads for alternative options, if needed. /// </summary> /// <param name="memoizer">The memoizer to use for caching <see cref="GetEvaluator(MemberInfo)"/> calls.</param> public MemoizingEvaluatorFactory(IMemoizer memoizer) { if (memoizer == null) { throw new ArgumentNullException(nameof(memoizer)); } _getEvaluator = memoizer.Memoize <MemberInfo, Delegate>(base.GetEvaluator); }
public MemberInfoSlimHashingVisitor(ExpressionSlimHasher parent, TypeSlimHashingVisitor typeHasher, IMemoizer memoizer) { _parent = parent; _typeHasher = typeHasher; // NB: We use reference equality for memoization in order to prevent the computation of another // hash code through the overridden GetHashCode implementation on MemberInfoSlim. The use // of reference equality is very effective within expressions and for reflection objects that // come from a shared reflection context where reference-equal objects are returned. _visitCache = memoizer.Memoize(base.Visit, MemoizationOptions.None, ReferenceEqualityComparer <MemberInfoSlim> .Instance); }
public async Task MemoizeAsync_BackgroundRefreshFails_LastGoodValueStillReturned() { TimeSpan refreshTime = TimeSpan.FromMinutes(1); var refreshTask = new TaskCompletionSource <Thing>(); var args = new object[] { "someString" }; var dataSource = CreateDataSource(5, refreshTask); IMemoizer memoizer = CreateMemoizer(CreateCache()); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, args, GetPolicy())).Id.ShouldBe(5); // fake that refreshTime has passed TimeFake.UtcNow += refreshTime; // Refresh task hasn't finished, should get old value (5) (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, args, GetPolicy())).Id.ShouldBe(5); // value is not refreshed yet. it is running on background // Complete refresh task and verify new value refreshTask.SetException(new Exception("Boo!!")); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, args, GetPolicy())).Id.ShouldBe(5); // new value is expected now }
/// <summary> /// Memoizes the specified <paramref name="function"/> using the specified <paramref name="memoizer"/>. /// </summary> /// <typeparam name="T">Type of the function argument.</typeparam> /// <typeparam name="TResult">Type of the function result.</typeparam> /// <param name="memoizer">The memoizer used to memoize the function.</param> /// <param name="function">The function to memoize.</param> /// <param name="options">Flags to influence the memoization behavior.</param> /// <returns>A memoized delegate containing the memoized function and providing access to the memoization cache.</returns> public static IMemoizedDelegate <Func <T, TResult> > Memoize <T, TResult>(this IMemoizer memoizer, Func <T, TResult> function, MemoizationOptions options = MemoizationOptions.None) { if (memoizer == null) { throw new ArgumentNullException(nameof(memoizer)); } if (function == null) { throw new ArgumentNullException(nameof(function)); } return(memoizer.Memoize <T, TResult>(function, options, comparer: null)); }
/// <summary> /// Memoizes the specified <paramref name="function"/> using the specified <paramref name="memoizer"/>. /// </summary> /// <typeparam name="TResult">Type of the function result.</typeparam> /// <param name="memoizer">The memoizer used to memoize the function.</param> /// <param name="function">The function to memoize.</param> /// <param name="options">Flags to influence the memoization behavior.</param> /// <returns>A memoized delegate containing the memoized function and providing access to the memoization cache.</returns> public static IMemoizedDelegate <Func <TResult> > Memoize <TResult>(this IMemoizer memoizer, Func <TResult> function, MemoizationOptions options = MemoizationOptions.None) { if (memoizer == null) { throw new ArgumentNullException(nameof(memoizer)); } if (function == null) { throw new ArgumentNullException(nameof(function)); } var res = memoizer.Memoize <object, TResult>(_ => function(), options, comparer: null); var del = res.Delegate; return(new MemoizedDelegate <Func <TResult> >(() => del(null), res.Cache)); }
public async Task MemoizeAsync_BackgroundRefreshFails_NextRequestAfterDelayTriggersRefresh() { TimeSpan refreshTime = TimeSpan.FromMinutes(1); TimeSpan failedRefreshDelay = TimeSpan.FromSeconds(1); var refreshTask = new TaskCompletionSource <Thing>(); var args = new object[] { "someString" }; string firstValue = "first Value"; string secondValue = "second Value"; var dataSource = CreateDataSource(firstValue, refreshTask, secondValue); IMemoizer memoizer = CreateMemoizer(CreateCache()); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, args, GetPolicy())).Id.ShouldBe(firstValue); // fake that refreshTime has passed TimeFake.UtcNow += refreshTime; // Should trigger refresh task that won't be completed yet, should get old value (5) (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, args, GetPolicy())).Id.ShouldBe(firstValue); // Fail the first refresh task and verify old value (5) still returned. // FailedRefreshDelay hasn't passed so shouldn't trigger refresh. refreshTask.SetException(new Exception("Boo!!")); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, args, GetPolicy())).Id.ShouldBe(firstValue); TimeFake.UtcNow += TimeSpan.FromMilliseconds(failedRefreshDelay.TotalMilliseconds * 0.7); // FailedRefreshDelay still hasn't passed so shouldn't trigger refresh. (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, args, GetPolicy())).Id.ShouldBe(firstValue); TimeFake.UtcNow += TimeSpan.FromMilliseconds(failedRefreshDelay.TotalMilliseconds * 0.7); // FailedRefreshDelay passed so should trigger refresh. (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, args, GetPolicy())).Id.ShouldBe(firstValue); // Second refresh should succeed, should get new value (7); (await(Task <Thing>) memoizer.Memoize(dataSource, ThingifyTaskThing, args, GetPolicy())).Id.ShouldBe(secondValue); }
private async Task <Revocable <Thing> > CallWithMemoize(IMemoizer memoizer, IThingFrobber dataSource) { return(await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetPolicy())); }
public static U Memoize <U>(this IMemoizer memo, Func <U> f) where U : class { return(memo.Memoize(memo, x => f())); }