New: All setting values are cached for better responsiveness.

This commit is contained in:
kay.one 2012-02-11 16:01:52 -08:00
parent 2051c9d911
commit 6df184b7cb
6 changed files with 101 additions and 24 deletions

View File

@ -1,7 +1,9 @@
using System; using System;
using System.IO; using System.IO;
using NUnit.Framework;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Test.Common; using NzbDrone.Test.Common;
using PetaPoco; using PetaPoco;
@ -60,5 +62,11 @@ namespace NzbDrone.Core.Test.Framework
return new ProgressNotification("Mock notification"); return new ProgressNotification("Mock notification");
} }
} }
[TearDown]
public void CoreTestTearDown()
{
ConfigProvider.ClearCache();
}
} }
} }

View File

@ -113,6 +113,7 @@
<Compile Include="JobTests\BannerDownloadJobTest.cs" /> <Compile Include="JobTests\BannerDownloadJobTest.cs" />
<Compile Include="JobTests\RecentBacklogSearchJobTest.cs" /> <Compile Include="JobTests\RecentBacklogSearchJobTest.cs" />
<Compile Include="ProviderTests\AnalyticsProviderTests\AnalyticsProviderFixture.cs" /> <Compile Include="ProviderTests\AnalyticsProviderTests\AnalyticsProviderFixture.cs" />
<Compile Include="ProviderTests\ConfigProviderTests\ConfigCachingFixture.cs" />
<Compile Include="ProviderTests\DecisionEngineTests\QualityAllowedByProfileSpecificationFixtrue.cs" /> <Compile Include="ProviderTests\DecisionEngineTests\QualityAllowedByProfileSpecificationFixtrue.cs" />
<Compile Include="ProviderTests\DecisionEngineTests\UpgradeHistorySpecificationFixtrue.cs" /> <Compile Include="ProviderTests\DecisionEngineTests\UpgradeHistorySpecificationFixtrue.cs" />
<Compile Include="ProviderTests\DecisionEngineTests\UpgradeDiskSpecificationFixtrue.cs" /> <Compile Include="ProviderTests\DecisionEngineTests\UpgradeDiskSpecificationFixtrue.cs" />
@ -172,7 +173,7 @@
<Compile Include="ProviderTests\IndexerProviderTest.cs" /> <Compile Include="ProviderTests\IndexerProviderTest.cs" />
<Compile Include="ProviderTests\HistoryProviderTest.cs" /> <Compile Include="ProviderTests\HistoryProviderTest.cs" />
<Compile Include="ProviderTests\MediaFileProviderTest.cs" /> <Compile Include="ProviderTests\MediaFileProviderTest.cs" />
<Compile Include="ProviderTests\ConfigProviderTest.cs" /> <Compile Include="ProviderTests\ConfigProviderTests\ConfigProviderFixture.cs" />
<Compile Include="ProviderTests\EpisodeProviderTest.cs" /> <Compile Include="ProviderTests\EpisodeProviderTest.cs" />
<Compile Include="Framework\TestDbHelper.cs" /> <Compile Include="Framework\TestDbHelper.cs" />
<Compile Include="ParserTest.cs" /> <Compile Include="ParserTest.cs" />

View File

@ -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<IDatabase>().Setup(c => c.Fetch<Config>())
.Returns(new List<Config> { new Config { Key = "Key1", Value = "Value1" } });
}
[Test]
public void getting_value_more_than_once_should_hit_db_once()
{
Mocker.Resolve<ConfigProvider>().GetValue("Key1", null).Should().Be("Value1");
Mocker.Resolve<ConfigProvider>().GetValue("Key1", null).Should().Be("Value1");
Mocker.Resolve<ConfigProvider>().GetValue("Key1", null).Should().Be("Value1");
Mocker.GetMock<IDatabase>().Verify(c => c.Fetch<Config>(), Times.Once());
}
}
}

View File

@ -6,11 +6,11 @@ using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.ProviderTests namespace NzbDrone.Core.Test.ProviderTests.ConfigProviderTests
{ {
[TestFixture] [TestFixture]
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
public class ConfigProviderTest : CoreTest public class ConfigProviderFixture : CoreTest
{ {
[SetUp] [SetUp]
public void SetUp() public void SetUp()
@ -134,6 +134,15 @@ namespace NzbDrone.Core.Test.ProviderTests
guid.Should().NotBeEmpty(); guid.Should().NotBeEmpty();
} }
[Test]
public void updating_a_vakye_should_update_its_value()
{
Mocker.Resolve<ConfigProvider>().SabHost = "Test";
Mocker.Resolve<ConfigProvider>().SabHost.Should().Be("Test");
Mocker.Resolve<ConfigProvider>().SabHost = "Test2";
Mocker.Resolve<ConfigProvider>().SabHost.Should().Be("Test2");
}
[Test] [Test]
[Description("This test will use reflection to ensure each config property read/writes to a unique key")] [Description("This test will use reflection to ensure each config property read/writes to a unique key")]

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Ninject; using Ninject;
using NLog; using NLog;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
@ -11,7 +12,10 @@ namespace NzbDrone.Core.Providers.Core
{ {
public class ConfigProvider public class ConfigProvider
{ {
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger logger = LogManager.GetCurrentClassLogger();
private static Dictionary<string, string> cache = new Dictionary<string, string>();
private readonly IDatabase _database; private readonly IDatabase _database;
[Inject] [Inject]
@ -24,7 +28,7 @@ namespace NzbDrone.Core.Providers.Core
{ {
} }
public IList<Config> All() public IEnumerable<Config> All()
{ {
return _database.Fetch<Config>(); return _database.Fetch<Config>();
} }
@ -409,7 +413,7 @@ namespace NzbDrone.Core.Providers.Core
set { SetValue("AutoIgnorePreviouslyDownloadedEpisodes", value); } set { SetValue("AutoIgnorePreviouslyDownloadedEpisodes", value); }
} }
public Guid UGuid public Guid UGuid
{ {
get { return Guid.Parse(GetValue("UGuid", Guid.NewGuid().ToString(), persist: true)); } 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) public virtual string GetValue(string key, object defaultValue, bool persist = false)
{ {
var dbValue = _database.SingleOrDefault<Config>("WHERE [Key] =@0", key); EnsureCache();
if (dbValue != null && !String.IsNullOrEmpty(dbValue.Value))
return dbValue.Value;
Logger.Trace("Unable to find config key '{0}' defaultValue:'{1}'", key, defaultValue); string dbValue;
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);
if (persist) if (persist)
SetValue(key, defaultValue.ToString()); SetValue(key, defaultValue.ToString());
@ -479,7 +486,7 @@ namespace NzbDrone.Core.Providers.Core
if (value == null) if (value == null)
throw new ArgumentNullException("key"); 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<Config>("WHERE [KEY]=@0", key); var dbValue = _database.SingleOrDefault<Config>("WHERE [KEY]=@0", key);
@ -490,12 +497,29 @@ namespace NzbDrone.Core.Providers.Core
else else
{ {
dbValue.Value = value; dbValue.Value = value;
using (var tran = _database.GetTransaction()) _database.Update(dbValue);
}
ClearCache();
}
private void EnsureCache()
{
lock (cache)
{
if (!cache.Any())
{ {
_database.Update(dbValue); cache = _database.Fetch<Config>().ToDictionary(c => c.Key, c => c.Value);
tran.Complete();
} }
} }
} }
public static void ClearCache()
{
lock (cache)
{
cache = new Dictionary<string, string>();
}
}
} }
} }

View File

@ -48,13 +48,13 @@ namespace NzbDrone.Web.Controllers
var jobs = _jobProvider.All().Select(j => new JobModel var jobs = _jobProvider.All().Select(j => new JobModel
{ {
Id = j.Id, Id = j.Id,
Enable = j.Enable, Enable = j.Enable,
TypeName = j.TypeName, TypeName = j.TypeName,
Name = j.Name, Name = j.Name,
Interval = j.Interval, Interval = j.Interval,
LastExecution = j.LastExecution.ToString(), LastExecution = j.LastExecution.ToString(),
Success = j.Success Success = j.Success
}).OrderBy(j => j.Interval); }).OrderBy(j => j.Interval);
var serializedJobs = new JavaScriptSerializer().Serialize(jobs); var serializedJobs = new JavaScriptSerializer().Serialize(jobs);
@ -84,9 +84,9 @@ namespace NzbDrone.Web.Controllers
return Json(new return Json(new
{ {
iTotalRecords = config.Count, iTotalRecords = config.Count(),
iTotalDisplayRecords = config.Count, iTotalDisplayRecords = config.Count(),
aaData = config aaData = config
}, JsonRequestBehavior.AllowGet); }, JsonRequestBehavior.AllowGet);
} }