Adding clock based cache invalidation

--HG--
branch : dev
This commit is contained in:
Sebastien Ros
2010-11-09 11:17:09 -08:00
parent 0fcd6864f9
commit 8f6ddfab94
4 changed files with 134 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
using System;
using Autofac;
using NUnit.Framework;
using Orchard.Caching;
using Orchard.Services;
using Orchard.Tests.Stubs;
namespace Orchard.Tests.Caching {
[TestFixture]
public class ClockCachingTests {
private IContainer _container;
private ICacheManager _cacheManager;
private StubClock _clock;
[SetUp]
public void Init() {
var builder = new ContainerBuilder();
builder.RegisterModule(new CacheModule());
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
builder.RegisterInstance<IClock>(_clock = new StubClock());
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
_container = builder.Build();
_cacheManager = _container.Resolve<ICacheManager>(new TypedParameter(typeof(Type), GetType()));
}
[Test]
public void WhenAbsoluteShouldHandleAbsoluteTime() {
var inOneSecond = _clock.UtcNow.AddSeconds(1);
var cached = 0;
// each call after the specified datetime will be reevaluated
Func<int> retrieve = ()
=> _cacheManager.Get("testItem",
ctx => {
ctx.Monitor(_clock.WhenUtc(inOneSecond));
return ++cached;
});
Assert.That(retrieve(), Is.EqualTo(1));
for ( var i = 0; i < 10; i++ ) {
Assert.That(retrieve(), Is.EqualTo(1));
}
_clock.Advance(TimeSpan.FromSeconds(1));
Assert.That(retrieve(), Is.EqualTo(2));
Assert.That(retrieve(), Is.EqualTo(3));
Assert.That(retrieve(), Is.EqualTo(4));
}
[Test]
public void WhenAbsoluteShouldHandleAbsoluteTimeSpan() {
var cached = 0;
// each cached value has a lifetime of the specified duration
Func<int> retrieve = ()
=> _cacheManager.Get("testItem",
ctx => {
ctx.Monitor(_clock.When(TimeSpan.FromSeconds(1)));
return ++cached;
});
Assert.That(retrieve(), Is.EqualTo(1));
for ( var i = 0; i < 10; i++ ) {
Assert.That(retrieve(), Is.EqualTo(1));
}
_clock.Advance(TimeSpan.FromSeconds(1));
for ( var i = 0; i < 10; i++ ) {
Assert.That(retrieve(), Is.EqualTo(2));
}
_clock.Advance(TimeSpan.FromSeconds(1));
for ( var i = 0; i < 10; i++ ) {
Assert.That(retrieve(), Is.EqualTo(3));
}
}
}
}

View File

@@ -160,6 +160,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="Caching\CacheScopeTests.cs" /> <Compile Include="Caching\CacheScopeTests.cs" />
<Compile Include="Caching\CacheTests.cs" /> <Compile Include="Caching\CacheTests.cs" />
<Compile Include="Caching\ClockCachingTests.cs" />
<Compile Include="Commands\CommandHandlerDescriptorBuilderTests.cs" /> <Compile Include="Commands\CommandHandlerDescriptorBuilderTests.cs" />
<Compile Include="Commands\CommandHandlerTests.cs" /> <Compile Include="Commands\CommandHandlerTests.cs" />
<Compile Include="Commands\CommandManagerTests.cs" /> <Compile Include="Commands\CommandManagerTests.cs" />

View File

@@ -1,4 +1,5 @@
using System; using System;
using Orchard.Caching;
using Orchard.Services; using Orchard.Services;
namespace Orchard.Tests.Stubs { namespace Orchard.Tests.Stubs {
@@ -16,5 +17,14 @@ namespace Orchard.Tests.Stubs {
public DateTime FutureMoment(TimeSpan span) { public DateTime FutureMoment(TimeSpan span) {
return UtcNow.Add(span); return UtcNow.Add(span);
} }
public IVolatileToken When(TimeSpan duration) {
return new Clock.AbsoluteExpirationToken(this, duration);
}
public IVolatileToken WhenUtc(DateTime absoluteUtc) {
return new Clock.AbsoluteExpirationToken(this, absoluteUtc);
}
} }
} }

View File

@@ -4,6 +4,16 @@ using Orchard.Caching;
namespace Orchard.Services { namespace Orchard.Services {
public interface IClock : IVolatileProvider { public interface IClock : IVolatileProvider {
DateTime UtcNow { get; } DateTime UtcNow { get; }
/// <summary>
/// Each retrieved value is cached during the specified amount of time.
/// </summary>
IVolatileToken When(TimeSpan duration);
/// <summary>
/// The cache is active until the specified time. Each subsequent access won't be cached.
/// </summary>
IVolatileToken WhenUtc(DateTime absoluteUtc);
} }
public class Clock : IClock { public class Clock : IClock {
@@ -11,5 +21,33 @@ namespace Orchard.Services {
get { return DateTime.UtcNow; } get { return DateTime.UtcNow; }
} }
public IVolatileToken When(TimeSpan duration) {
return new AbsoluteExpirationToken(this, duration);
}
public IVolatileToken WhenUtc(DateTime absoluteUtc) {
return new AbsoluteExpirationToken(this, absoluteUtc);
}
public class AbsoluteExpirationToken : IVolatileToken {
private readonly IClock _clock;
private readonly DateTime _invalidateUtc;
public AbsoluteExpirationToken(IClock clock, DateTime invalidateUtc) {
_clock = clock;
_invalidateUtc = invalidateUtc;
}
public AbsoluteExpirationToken(IClock clock, TimeSpan duration) {
_clock = clock;
_invalidateUtc = _clock.UtcNow.Add(duration);
}
public bool IsCurrent {
get {
return _clock.UtcNow < _invalidateUtc;
}
}
}
} }
} }