diff --git a/NzbDrone.Core.Test/Framework/CoreTest.cs b/NzbDrone.Core.Test/Framework/CoreTest.cs
index 0aed5ed31..558d5402f 100644
--- a/NzbDrone.Core.Test/Framework/CoreTest.cs
+++ b/NzbDrone.Core.Test/Framework/CoreTest.cs
@@ -1,7 +1,9 @@
using System;
using System.IO;
+using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Model.Notification;
+using NzbDrone.Core.Providers.Core;
using NzbDrone.Test.Common;
using PetaPoco;
@@ -60,5 +62,11 @@ namespace NzbDrone.Core.Test.Framework
return new ProgressNotification("Mock notification");
}
}
+
+ [TearDown]
+ public void CoreTestTearDown()
+ {
+ ConfigProvider.ClearCache();
+ }
}
}
diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
index 96e742818..4a67ae872 100644
--- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
+++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
@@ -113,6 +113,7 @@
+
@@ -172,7 +173,7 @@
-
+
diff --git a/NzbDrone.Core.Test/ProviderTests/ConfigProviderTests/ConfigCachingFixture.cs b/NzbDrone.Core.Test/ProviderTests/ConfigProviderTests/ConfigCachingFixture.cs
new file mode 100644
index 000000000..f71184d43
--- /dev/null
+++ b/NzbDrone.Core.Test/ProviderTests/ConfigProviderTests/ConfigCachingFixture.cs
@@ -0,0 +1,35 @@
+using System.Collections.Generic;
+using System.Linq;
+using FluentAssertions;
+using Moq;
+using NUnit.Framework;
+using NzbDrone.Core.Providers.Core;
+using NzbDrone.Core.Repository;
+using NzbDrone.Core.Test.Framework;
+using PetaPoco;
+
+namespace NzbDrone.Core.Test.ProviderTests.ConfigProviderTests
+{
+ [TestFixture]
+ public class ConfigCachingFixture : CoreTest
+ {
+ [SetUp]
+ public void Setup()
+ {
+ Mocker.GetMock().Setup(c => c.Fetch())
+ .Returns(new List { new Config { Key = "Key1", Value = "Value1" } });
+
+ }
+
+ [Test]
+ public void getting_value_more_than_once_should_hit_db_once()
+ {
+ Mocker.Resolve().GetValue("Key1", null).Should().Be("Value1");
+ Mocker.Resolve().GetValue("Key1", null).Should().Be("Value1");
+ Mocker.Resolve().GetValue("Key1", null).Should().Be("Value1");
+
+ Mocker.GetMock().Verify(c => c.Fetch(), Times.Once());
+ }
+
+ }
+}
diff --git a/NzbDrone.Core.Test/ProviderTests/ConfigProviderTest.cs b/NzbDrone.Core.Test/ProviderTests/ConfigProviderTests/ConfigProviderFixture.cs
similarity index 92%
rename from NzbDrone.Core.Test/ProviderTests/ConfigProviderTest.cs
rename to NzbDrone.Core.Test/ProviderTests/ConfigProviderTests/ConfigProviderFixture.cs
index 480b7d873..7436a00dc 100644
--- a/NzbDrone.Core.Test/ProviderTests/ConfigProviderTest.cs
+++ b/NzbDrone.Core.Test/ProviderTests/ConfigProviderTests/ConfigProviderFixture.cs
@@ -6,11 +6,11 @@ using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework;
-namespace NzbDrone.Core.Test.ProviderTests
+namespace NzbDrone.Core.Test.ProviderTests.ConfigProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
- public class ConfigProviderTest : CoreTest
+ public class ConfigProviderFixture : CoreTest
{
[SetUp]
public void SetUp()
@@ -134,6 +134,15 @@ namespace NzbDrone.Core.Test.ProviderTests
guid.Should().NotBeEmpty();
}
+ [Test]
+ public void updating_a_vakye_should_update_its_value()
+ {
+ Mocker.Resolve().SabHost = "Test";
+ Mocker.Resolve().SabHost.Should().Be("Test");
+
+ Mocker.Resolve().SabHost = "Test2";
+ Mocker.Resolve().SabHost.Should().Be("Test2");
+ }
[Test]
[Description("This test will use reflection to ensure each config property read/writes to a unique key")]
diff --git a/NzbDrone.Core/Providers/Core/ConfigProvider.cs b/NzbDrone.Core/Providers/Core/ConfigProvider.cs
index 1fb57dd9d..73dac070d 100644
--- a/NzbDrone.Core/Providers/Core/ConfigProvider.cs
+++ b/NzbDrone.Core/Providers/Core/ConfigProvider.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Ninject;
using NLog;
using NzbDrone.Core.Model;
@@ -11,7 +12,10 @@ namespace NzbDrone.Core.Providers.Core
{
public class ConfigProvider
{
- private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+ private static readonly Logger logger = LogManager.GetCurrentClassLogger();
+
+ private static Dictionary cache = new Dictionary();
+
private readonly IDatabase _database;
[Inject]
@@ -24,7 +28,7 @@ namespace NzbDrone.Core.Providers.Core
{
}
- public IList All()
+ public IEnumerable All()
{
return _database.Fetch();
}
@@ -409,7 +413,7 @@ namespace NzbDrone.Core.Providers.Core
set { SetValue("AutoIgnorePreviouslyDownloadedEpisodes", value); }
}
- public Guid UGuid
+ public Guid UGuid
{
get { return Guid.Parse(GetValue("UGuid", Guid.NewGuid().ToString(), persist: true)); }
}
@@ -449,12 +453,15 @@ namespace NzbDrone.Core.Providers.Core
public virtual string GetValue(string key, object defaultValue, bool persist = false)
{
- var dbValue = _database.SingleOrDefault("WHERE [Key] =@0", key);
+ EnsureCache();
+
+
+ string dbValue;
- if (dbValue != null && !String.IsNullOrEmpty(dbValue.Value))
- return dbValue.Value;
+ if (cache.TryGetValue(key, out dbValue) && dbValue != null && !String.IsNullOrEmpty(dbValue))
+ return dbValue;
- Logger.Trace("Unable to find config key '{0}' defaultValue:'{1}'", key, defaultValue);
+ logger.Trace("Unable to find config key '{0}' defaultValue:'{1}'", key, defaultValue);
if (persist)
SetValue(key, defaultValue.ToString());
@@ -479,7 +486,7 @@ namespace NzbDrone.Core.Providers.Core
if (value == null)
throw new ArgumentNullException("key");
- Logger.Trace("Writing Setting to file. Key:'{0}' Value:'{1}'", key, value);
+ logger.Trace("Writing Setting to file. Key:'{0}' Value:'{1}'", key, value);
var dbValue = _database.SingleOrDefault("WHERE [KEY]=@0", key);
@@ -490,12 +497,29 @@ namespace NzbDrone.Core.Providers.Core
else
{
dbValue.Value = value;
- using (var tran = _database.GetTransaction())
+ _database.Update(dbValue);
+ }
+
+ ClearCache();
+ }
+
+ private void EnsureCache()
+ {
+ lock (cache)
+ {
+ if (!cache.Any())
{
- _database.Update(dbValue);
- tran.Complete();
+ cache = _database.Fetch().ToDictionary(c => c.Key, c => c.Value);
}
}
}
+
+ public static void ClearCache()
+ {
+ lock (cache)
+ {
+ cache = new Dictionary();
+ }
+ }
}
}
diff --git a/NzbDrone.Web/Controllers/SystemController.cs b/NzbDrone.Web/Controllers/SystemController.cs
index f1217d02e..46fa0f071 100644
--- a/NzbDrone.Web/Controllers/SystemController.cs
+++ b/NzbDrone.Web/Controllers/SystemController.cs
@@ -48,13 +48,13 @@ namespace NzbDrone.Web.Controllers
var jobs = _jobProvider.All().Select(j => new JobModel
{
- Id = j.Id,
- Enable = j.Enable,
- TypeName = j.TypeName,
- Name = j.Name,
- Interval = j.Interval,
- LastExecution = j.LastExecution.ToString(),
- Success = j.Success
+ Id = j.Id,
+ Enable = j.Enable,
+ TypeName = j.TypeName,
+ Name = j.Name,
+ Interval = j.Interval,
+ LastExecution = j.LastExecution.ToString(),
+ Success = j.Success
}).OrderBy(j => j.Interval);
var serializedJobs = new JavaScriptSerializer().Serialize(jobs);
@@ -84,9 +84,9 @@ namespace NzbDrone.Web.Controllers
return Json(new
{
- iTotalRecords = config.Count,
- iTotalDisplayRecords = config.Count,
- aaData = config
+ iTotalRecords = config.Count(),
+ iTotalDisplayRecords = config.Count(),
+ aaData = config
}, JsonRequestBehavior.AllowGet);
}