Added db4o.

Added guards against most problematic areas.
This commit is contained in:
kay.one 2013-02-02 11:39:27 -08:00
parent b6a4e6c32c
commit 5dbaaee005
11 changed files with 396 additions and 6 deletions

View File

@ -0,0 +1,54 @@
using System.Linq;
using System;
using System.Collections.Generic;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using Db4objects.Db4o.Linq;
namespace NzbDrone.Core.Test.Datastore
{
[TestFixture]
public class ObjectDatabaseFixture : CoreTest
{
[SetUp]
public void SetUp()
{
WithObjectDb();
}
[Test]
public void should_be_able_to_write_to_database()
{
var series = Builder<Series>.CreateNew().Build();
ObjDb.Save(series);
ObjDb.Ext().Purge();
ObjDb.AsQueryable<Series>().Should().HaveCount(1);
}
[Test]
public void should_not_store_dirty_data_in_cache()
{
var episode = Builder<Episode>.CreateNew().Build();
//Save series without episode attached
ObjDb.Save(episode);
ObjDb.AsQueryable<Episode>().Single().Series.Should().BeNull();
episode.Series = Builder<Series>.CreateNew().Build();
ObjDb.AsQueryable<Episode>().Single().Series.Should().BeNull();
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.IO;
using Db4objects.Db4o.IO;
using NUnit.Framework;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Model.Notification;
@ -9,14 +10,14 @@ using PetaPoco;
namespace NzbDrone.Core.Test.Framework
{
public class CoreTest : TestBase
public abstract class CoreTest : TestBase
{
private string _dbTemplateName;
[SetUp]
public void CoreTestSetup()
{
if(NCrunch.Framework.NCrunchEnvironment.NCrunchIsResident())
if (NCrunch.Framework.NCrunchEnvironment.NCrunchIsResident())
{
_dbTemplateName = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()) + ".sdf";
}
@ -24,6 +25,7 @@ namespace NzbDrone.Core.Test.Framework
{
_dbTemplateName = "db_template.sdf";
}
CreateDataBaseTemplate();
}
@ -71,12 +73,32 @@ namespace NzbDrone.Core.Test.Framework
}
}
private IObjectDbSession _objDb;
protected IObjectDbSession ObjDb
{
get
{
if (_objDb == null)
throw new InvalidOperationException("Test object database doesn't exists. Make sure you call WithRealDb() if you intend to use an actual database.");
return _objDb;
}
}
protected void WithRealDb()
{
_db = GetEmptyDatabase();
Mocker.SetConstant(Db);
}
protected void WithObjectDb()
{
_objDb = new ObjectDbSessionFactory().Create(new PagingMemoryStorage());
Mocker.SetConstant(ObjDb);
}
protected static ProgressNotification MockNotification
{
get
@ -106,6 +128,11 @@ namespace NzbDrone.Core.Test.Framework
}
catch (IOException) { }
}
if (_objDb != null)
{
_objDb.Dispose();
}
}
}
}

View File

@ -65,6 +65,15 @@
<Reference Include="AutoMoq">
<HintPath>..\packages\AutoMoq.1.6.1\lib\AutoMoq.dll</HintPath>
</Reference>
<Reference Include="Db4objects.Db4o">
<HintPath>..\packages\db4o-devel.8.1.184.15492\lib\net40\Db4objects.Db4o.dll</HintPath>
</Reference>
<Reference Include="Db4objects.Db4o.Data.Services">
<HintPath>..\packages\db4o-devel.8.1.184.15492\lib\net40\Db4objects.Db4o.Data.Services.dll</HintPath>
</Reference>
<Reference Include="Db4objects.Db4o.Linq">
<HintPath>..\packages\db4o-devel.8.1.184.15492\lib\net40\Db4objects.Db4o.Linq.dll</HintPath>
</Reference>
<Reference Include="DeskMetrics.NET, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libraries\DeskMetrics\DeskMetrics.NET.dll</HintPath>
@ -88,6 +97,9 @@
<Reference Include="Microsoft.Practices.Unity.Configuration">
<HintPath>..\packages\Unity.2.1.505.2\lib\NET35\Microsoft.Practices.Unity.Configuration.dll</HintPath>
</Reference>
<Reference Include="Mono.Reflection">
<HintPath>..\packages\db4o-devel.8.1.184.15492\lib\net40\Mono.Reflection.dll</HintPath>
</Reference>
<Reference Include="Moq, Version=4.0.10827.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<HintPath>..\packages\Moq.4.0.10827\lib\NET40\Moq.dll</HintPath>
</Reference>
@ -134,6 +146,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Datastore\ObjectDatabaseFixture.cs" />
<Compile Include="Framework\CoreTestTSubject.cs" />
<Compile Include="HelperTests\XElementHelperTests\ConvertToTFixture.cs" />
<Compile Include="IndexerTests\NzbxFixture.cs" />

View File

@ -3,6 +3,7 @@
<package id="Autofac" version="2.6.3.862" targetFramework="net40" />
<package id="AutoMoq" version="1.6.1" targetFramework="net40" />
<package id="CommonServiceLocator" version="1.0" targetFramework="net40" />
<package id="db4o-devel" version="8.1.184.15492" targetFramework="net40" />
<package id="FluentAssertions" version="2.0.0.1" targetFramework="net40" />
<package id="Microsoft.SqlServer.Compact" version="4.0.8876.1" targetFramework="net40" />
<package id="Moq" version="4.0.10827" />

View File

@ -1,6 +1,10 @@
using System;
using System;
using System.Data.Common;
using System.Data.SqlServerCe;
using Db4objects.Db4o;
using Db4objects.Db4o.IO;
using Db4objects.Db4o.Internal;
using Db4objects.Db4o.Internal.Config;
using StackExchange.Profiling;
using StackExchange.Profiling.Data;
@ -23,4 +27,23 @@ namespace NzbDrone.Core.Datastore
return connection;
}
}
public class ObjectDbSessionFactory
{
public IObjectDbSession Create(IStorage storage = null)
{
if (storage == null)
{
storage = new FileStorage();
}
var config = Db4oEmbedded.NewConfiguration();
config.File.Storage = storage;
var objectContainer = Db4oEmbedded.OpenFile(config, "nzbdrone.db4o");
return new ObjectDbSession((ObjectContainerBase)objectContainer);
}
}
}

View File

@ -0,0 +1,142 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Db4objects.Db4o;
using Db4objects.Db4o.Internal;
using Db4objects.Db4o.Internal.References;
namespace NzbDrone.Core.Datastore
{
public interface IObjectDbSession : IObjectContainer
{
void Save(object obj);
void Save(object obj, int depth);
void SaveAll<T>(Transaction transaction, IEnumerator<T> objects);
void Update(object obj);
void Update(object obj, int depth);
void UpdateAll<T>(Transaction transaction, IEnumerator<T> objects);
}
public class ObjectDbSession : ObjectContainerSession, IObjectDbSession
{
private NoCahceRefrenceSystem _noCacheRefSystem;
public ObjectDbSession(ObjectContainerBase server)
: base(server, server.NewTransaction(server.SystemTransaction(), new NoCahceRefrenceSystem(), false))
{
_transaction.SetOutSideRepresentation(this);
_noCacheRefSystem = (NoCahceRefrenceSystem)_transaction.ReferenceSystem();
}
public override void Store(object obj)
{
throw new InvalidOperationException("Store is not supported. please use Save() or Update()");
}
public override void StoreAll(Transaction transaction, IEnumerator objects)
{
throw new InvalidOperationException("Store is not supported. please use Save() or Update()");
}
public override void Store(object obj, int depth)
{
throw new InvalidOperationException("Store is not supported. please use Save() or Update()");
}
public void Save(object obj)
{
ValidateSave(obj);
base.Store(obj);
Commit();
}
public void Save(object obj, int depth)
{
ValidateSave(obj);
base.Store(obj, depth);
Commit();
}
public void SaveAll<T>(Transaction transaction, IEnumerator<T> objects)
{
var obj = objects.ToIEnumerable().ToList();
obj.ForEach(c => ValidateSave(c));
base.StoreAll(transaction, obj.GetEnumerator());
Commit();
}
public void Update(object obj)
{
ValidateUpdate(obj);
base.Store(obj);
Commit();
}
public void Update(object obj, int depth)
{
ValidateUpdate(obj);
base.Store(obj, depth);
Commit();
}
public void UpdateAll<T>(Transaction transaction, IEnumerator<T> objects)
{
var obj = objects.ToIEnumerable().ToList();
obj.ForEach(c => ValidateUpdate(c));
base.StoreAll(transaction, obj.GetEnumerator());
Commit();
}
public void UpdateAll(Transaction transaction, IEnumerator objects)
{
throw new NotImplementedException();
}
public new void Purge()
{
_noCacheRefSystem.Reset();
}
private void ValidateSave(object obj)
{
if (IsAttached(obj))
{
throw new InvalidOperationException("Attempted to save an object that is already attached to database");
}
}
private void ValidateUpdate(object obj)
{
if (!IsAttached(obj))
{
throw new InvalidOperationException("Attempted to update an object that is not attached to database");
}
}
private bool IsAttached(object obj)
{
return base.Ext().GetID(obj) > 0;
}
}
public static class Ext
{
public static IEnumerable<T> ToIEnumerable<T>(this IEnumerator<T> enumerator)
{
while (enumerator.MoveNext())
{
yield return enumerator.Current;
}
}
}
}

View File

@ -0,0 +1,116 @@
using System.Linq;
using Db4objects.Db4o;
using Db4objects.Db4o.Foundation;
using Db4objects.Db4o.Internal;
using Db4objects.Db4o.Internal.References;
namespace NzbDrone.Core.Datastore
{
public class NoCahceRefrenceSystem : IReferenceSystem
{
private ObjectReference _hashCodeTree;
private ObjectReference _idTree;
internal NoCahceRefrenceSystem()
{
}
public virtual void AddNewReference(ObjectReference @ref)
{
AddReference(@ref);
}
public virtual void AddExistingReference(ObjectReference @ref)
{
AddReference(@ref);
}
public virtual void Commit()
{
Reset();
}
public virtual ObjectReference ReferenceForId(int id)
{
if (DTrace.enabled)
DTrace.GetYapobject.Log(id);
if (_idTree == null)
return null;
if (!ObjectReference.IsValidId(id))
return null;
else
return _idTree.Id_find(id);
}
public virtual ObjectReference ReferenceForObject(object obj)
{
if (_hashCodeTree == null)
return null;
else
return _hashCodeTree.Hc_find(obj);
}
public virtual void RemoveReference(ObjectReference @ref)
{
if (DTrace.enabled)
DTrace.ReferenceRemoved.Log(@ref.GetID());
if (_hashCodeTree != null)
_hashCodeTree = _hashCodeTree.Hc_remove(@ref);
if (_idTree == null)
return;
_idTree = _idTree.Id_remove(@ref);
}
public virtual void Rollback()
{
Reset();
}
public virtual void TraverseReferences(IVisitor4 visitor)
{
if (_hashCodeTree == null)
return;
_hashCodeTree.Hc_traverse(visitor);
}
public virtual void Discarded()
{
}
public void Reset()
{
_hashCodeTree = null;
_idTree = null;
}
private void AddReference(ObjectReference @ref)
{
@ref.Ref_init();
IdAdd(@ref);
HashCodeAdd(@ref);
}
private void HashCodeAdd(ObjectReference @ref)
{
if (_hashCodeTree == null)
_hashCodeTree = @ref;
else
_hashCodeTree = _hashCodeTree.Hc_add(@ref);
}
private void IdAdd(ObjectReference @ref)
{
if (DTrace.enabled)
DTrace.IdTreeAdd.Log(@ref.GetID());
if (_idTree == null)
_idTree = @ref;
else
_idTree = _idTree.Id_add(@ref);
}
}
}

View File

@ -133,6 +133,15 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\DataTables.Mvc.Core.0.1.0.85\lib\DataTables.Mvc.Core.dll</HintPath>
</Reference>
<Reference Include="Db4objects.Db4o">
<HintPath>..\packages\db4o-devel.8.1.184.15492\lib\net40\Db4objects.Db4o.dll</HintPath>
</Reference>
<Reference Include="Db4objects.Db4o.Data.Services">
<HintPath>..\packages\db4o-devel.8.1.184.15492\lib\net40\Db4objects.Db4o.Data.Services.dll</HintPath>
</Reference>
<Reference Include="Db4objects.Db4o.Linq">
<HintPath>..\packages\db4o-devel.8.1.184.15492\lib\net40\Db4objects.Db4o.Linq.dll</HintPath>
</Reference>
<Reference Include="DeskMetrics.NET">
<HintPath>..\Libraries\DeskMetrics\DeskMetrics.NET.dll</HintPath>
</Reference>
@ -168,6 +177,9 @@
<Reference Include="MiniProfiler">
<HintPath>..\packages\MiniProfiler.2.0.2\lib\net40\MiniProfiler.dll</HintPath>
</Reference>
<Reference Include="Mono.Reflection">
<HintPath>..\packages\db4o-devel.8.1.184.15492\lib\net40\Mono.Reflection.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
@ -223,6 +235,8 @@
<Compile Include="Constants.cs" />
<Compile Include="ContainerExtentions.cs" />
<Compile Include="Datastore\ConnectionFactory.cs" />
<Compile Include="Datastore\NoCahceRefrenceSystem.cs" />
<Compile Include="Datastore\IObjectDbSession.cs" />
<Compile Include="Datastore\MigrationLogger.cs" />
<Compile Include="Datastore\MigrationsHelper.cs" />
<Compile Include="Datastore\CustomeMapper.cs" />

View File

@ -2,6 +2,7 @@
<packages>
<package id="Autofac" version="2.6.3.862" targetFramework="net40" />
<package id="DataTables.Mvc.Core" version="0.1.0.85" />
<package id="db4o-devel" version="8.1.184.15492" targetFramework="net40" />
<package id="DotNetZip" version="1.9.1.8" />
<package id="Growl" version="0.6" />
<package id="MediaInfoNet" version="0.3" targetFramework="net40" />

View File

@ -16,7 +16,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.8.0" newVersion="4.0.8.0" />
<bindingRedirect oldVersion="0.0.0.0-4.5.0.0" newVersion="4.5.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />

View File

@ -8,9 +8,8 @@ using NzbDrone.Test.Common.AutoMoq;
namespace NzbDrone.Test.Common
{
public class TestBase : LoggingTest
public abstract class TestBase : LoggingTest
{
protected const string INTEGRATION_TEST = "Integration Test";