From 098036d49ad15ebd5fed452966e071de4f2de9e2 Mon Sep 17 00:00:00 2001 From: Keivan Beigi Date: Tue, 30 Apr 2013 18:11:00 -0700 Subject: [PATCH] added new in memory cache. --- .../CacheTests/CachedFixture.cs | 74 +++++++++++++++++++ .../CacheTests/CachedManagerFixture.cs | 33 +++++++++ .../NzbDrone.Common.Test.csproj | 2 + NzbDrone.Common/Cache/CacheManger.cs | 22 ++++++ NzbDrone.Common/Cache/Cached.cs | 55 ++++++++++++++ NzbDrone.Common/Cache/ICached.cs | 13 ++++ NzbDrone.Common/NzbDrone.Common.csproj | 3 + 7 files changed, 202 insertions(+) create mode 100644 NzbDrone.Common.Test/CacheTests/CachedFixture.cs create mode 100644 NzbDrone.Common.Test/CacheTests/CachedManagerFixture.cs create mode 100644 NzbDrone.Common/Cache/CacheManger.cs create mode 100644 NzbDrone.Common/Cache/Cached.cs create mode 100644 NzbDrone.Common/Cache/ICached.cs diff --git a/NzbDrone.Common.Test/CacheTests/CachedFixture.cs b/NzbDrone.Common.Test/CacheTests/CachedFixture.cs new file mode 100644 index 000000000..6396bcc50 --- /dev/null +++ b/NzbDrone.Common.Test/CacheTests/CachedFixture.cs @@ -0,0 +1,74 @@ +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Common.Cache; + +namespace NzbDrone.Common.Test.CacheTests +{ + [TestFixture] + public class CachedFixture + { + private Cached _cachedString = new Cached(); + private Worker _worker; + + [SetUp] + public void SetUp() + { + _cachedString = new Cached(); + _worker = new Worker(); + } + + [Test] + public void should_call_function_once() + { + _cachedString.Get("Test", _worker.GetString); + _cachedString.Get("Test", _worker.GetString); + + _worker.HitCount.Should().Be(1); + + } + + + + [Test] + public void multiple_calls_should_return_same_result() + { + var first = _cachedString.Get("Test", _worker.GetString); + var second = _cachedString.Get("Test", _worker.GetString); + + first.Should().Be(second); + + } + + + [Test] + public void should_remove_value_from_set() + { + _cachedString.Get("Test", _worker.GetString); + + _cachedString.Remove("Test"); + + _cachedString.Get("Test", _worker.GetString); + + + _worker.HitCount.Should().Be(2); + + } + + [Test] + public void remove_none_existing_should_break_things() + { + _cachedString.Remove("Test"); + } + } + + public class Worker + { + public int HitCount { get; private set; } + + public string GetString() + { + HitCount++; + return "Hit count is " + HitCount; + } + } +} \ No newline at end of file diff --git a/NzbDrone.Common.Test/CacheTests/CachedManagerFixture.cs b/NzbDrone.Common.Test/CacheTests/CachedManagerFixture.cs new file mode 100644 index 000000000..60352d752 --- /dev/null +++ b/NzbDrone.Common.Test/CacheTests/CachedManagerFixture.cs @@ -0,0 +1,33 @@ +using System; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Common.Cache; + +namespace NzbDrone.Common.Test.CacheTests +{ + [TestFixture] + public class CachedManagerFixture + { + [Test] + public void should_return_proper_type_of_cache() + { + var result = CacheManger.GetCache(typeof(string)); + + result.Should().BeOfType>(); + } + + + [Test] + public void multiple_calls_should_get_the_same_cache() + { + var result1 = CacheManger.GetCache(typeof(string)); + var result2 = CacheManger.GetCache(typeof(string)); + + result1.Should().BeSameAs(result2); + } + + + + + } +} \ No newline at end of file diff --git a/NzbDrone.Common.Test/NzbDrone.Common.Test.csproj b/NzbDrone.Common.Test/NzbDrone.Common.Test.csproj index 04d816414..b52010006 100644 --- a/NzbDrone.Common.Test/NzbDrone.Common.Test.csproj +++ b/NzbDrone.Common.Test/NzbDrone.Common.Test.csproj @@ -78,6 +78,8 @@ + + diff --git a/NzbDrone.Common/Cache/CacheManger.cs b/NzbDrone.Common/Cache/CacheManger.cs new file mode 100644 index 000000000..97ace151d --- /dev/null +++ b/NzbDrone.Common/Cache/CacheManger.cs @@ -0,0 +1,22 @@ +using System; +using NzbDrone.Common.EnsureThat; + +namespace NzbDrone.Common.Cache +{ + public static class CacheManger + { + private static readonly ICached Cache; + + static CacheManger() + { + Cache = new Cached(); + } + + public static ICached GetCache(Type type) + { + Ensure.That(() => type).IsNotNull(); + + return (ICached)Cache.Get(type.FullName, () => new Cached()); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Common/Cache/Cached.cs b/NzbDrone.Common/Cache/Cached.cs new file mode 100644 index 000000000..9ec11872f --- /dev/null +++ b/NzbDrone.Common/Cache/Cached.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Concurrent; +using NzbDrone.Common.EnsureThat; + +namespace NzbDrone.Common.Cache +{ + public class Cached : ICached + { + private readonly ConcurrentDictionary _store; + + public Cached() + { + _store = new ConcurrentDictionary(); + } + + public void Set(string key, T value) + { + Ensure.That(() => key).IsNotNullOrWhiteSpace(); + _store.TryAdd(key, value); + } + + public T Get(string key, Func function) + { + Ensure.That(() => key).IsNotNullOrWhiteSpace(); + + T value; + + if (!_store.TryGetValue(key, out value)) + { + value = function(); + Set(key, value); + } + + return value; + } + + public bool ContainsKey(string key) + { + Ensure.That(() => key).IsNotNullOrWhiteSpace(); + return _store.ContainsKey(key); + } + + public void Clear() + { + _store.Clear(); + } + + public void Remove(string key) + { + Ensure.That(() => key).IsNotNullOrWhiteSpace(); + T value; + _store.TryRemove(key, out value); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Common/Cache/ICached.cs b/NzbDrone.Common/Cache/ICached.cs new file mode 100644 index 000000000..ab3142ac4 --- /dev/null +++ b/NzbDrone.Common/Cache/ICached.cs @@ -0,0 +1,13 @@ +using System; + +namespace NzbDrone.Common.Cache +{ + public interface ICached + { + void Set(string key, T value); + T Get(string key, Func function); + bool ContainsKey(string key); + void Clear(); + void Remove(string key); + } +} \ No newline at end of file diff --git a/NzbDrone.Common/NzbDrone.Common.csproj b/NzbDrone.Common/NzbDrone.Common.csproj index 542afc695..3d74e8885 100644 --- a/NzbDrone.Common/NzbDrone.Common.csproj +++ b/NzbDrone.Common/NzbDrone.Common.csproj @@ -84,6 +84,9 @@ + + +