Skip to content

Commit

Permalink
Add initial implementation of Jet-based storage engine
Browse files Browse the repository at this point in the history
  • Loading branch information
anaisbetts committed Dec 20, 2010
1 parent 34f72ae commit 35ef706
Show file tree
Hide file tree
Showing 4 changed files with 261 additions and 0 deletions.
140 changes: 140 additions & 0 deletions ReactiveXaml.Serialization.Esent/EsentStorageEngine.cs
@@ -0,0 +1,140 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Microsoft.Isam.Esent.Collections.Generic;

namespace ReactiveXaml.Serialization.Esent
{
public class EsentPersistedMetadata
{
public Dictionary<string, Guid> SyncPointIndex { get; set; }
public Dictionary<Guid, string> ItemTypeNames { get; set; }
}

public class EsentStorageEngine : IExtendedStorageEngine
{
PersistentDictionary<Guid, byte[]> _backingStore;
Dictionary<Guid, string> _itemTypeNames;
Dictionary<string, Guid> _syncPointIndex;

static readonly Lazy<IEnumerable<Type>> allStorageTypes = new Lazy<IEnumerable<Type>>(
() => Utility.GetAllTypesImplementingInterface(typeof(ISerializableItem)).ToArray());

Func<object, DataContractSerializationProvider> serializerFactory;

public EsentStorageEngine(string databasePath)
{
_backingStore = new PersistentDictionary<Guid, byte[]>(databasePath);
}

public T Load<T>(Guid contentHash) where T : ISerializableItem {
return (T)Load(contentHash);
}

public object Load(Guid contentHash)
{
byte[] data;

if (!_backingStore.TryGetValue(contentHash, out data)) {
this.Log().ErrorFormat("Failed to load object: {0}", contentHash);
return null;
}

this.Log().DebugFormat("Loaded {0}", contentHash);
return serializerFactory(contentHash).Deserialize(data, Type.GetType(_itemTypeNames[contentHash]));
}

public void Save<T>(T obj) where T : ISerializableItem
{
this.Log().DebugFormat("Saving {0}: {1}", obj, obj.ContentHash);
_itemTypeNames[obj.ContentHash] = obj.GetType().FullName;
_backingStore[obj.ContentHash] = serializerFactory(obj).Serialize(obj);
}

public void FlushChanges()
{
persistMetadata();
_backingStore.Flush();
}

public ISyncPointInformation CreateSyncPoint<T>(T obj, string qualifier = null, DateTimeOffset? createdOn = null)
where T : ISerializableItem
{
Save(obj);

var key = getKeyFromQualifiedType(typeof (T), qualifier ?? String.Empty);
var parent = (_syncPointIndex.ContainsKey(key) ? _syncPointIndex[key] : Guid.Empty);
var ret = new SyncPointInformation(obj.ContentHash, parent, typeof (T), qualifier ?? String.Empty, createdOn ?? DateTimeOffset.Now);
Save(ret);
_syncPointIndex[key] = ret.ContentHash;

this.Log().InfoFormat("Created sync point: {0}.{1}", obj.ContentHash, qualifier);

FlushChanges();
return ret;
}

public Guid[] GetOrderedRevisionList(Type type, string qualifier = null)
{
var ret = new List<Guid>();
var key = getKeyFromQualifiedType(type, qualifier ?? String.Empty);

if (!_syncPointIndex.ContainsKey(key)) {
return null;
}

var current = _syncPointIndex[key];
while(current != Guid.Empty) {
ret.Add(current);

var syncPoint = Load<ISyncPointInformation>(current);
current = syncPoint.ParentSyncPoint;
}

return ret.ToArray();
}

public void Dispose() {
FlushChanges();
_backingStore.Dispose();
}

public T GetLatestRootObject<T>(string qualifier = null, DateTimeOffset? olderThan = null) where T : ISerializableItem {
throw new NotImplementedException();
}

public T[] GetRootObjectsInDateRange<T>(string qualifier = null, DateTimeOffset? olderThan = null, DateTimeOffset? newerThan = null) where T : ISerializableItem {
throw new NotImplementedException();
}

static string getKeyFromQualifiedType(Type type, string qualifier)
{
return String.Format(CultureInfo.InvariantCulture, "{0}_{1}", type.FullName, qualifier);
}

void loadOrInitializeMetadata()
{
byte[] data;

if (!_backingStore.TryGetValue(Guid.Empty, out data)) {
if (_backingStore.Count != 0) {
this.Log().Fatal("Database has been corrupted!");
throw new Exception("Database is in an inconsistent state");
}

this.Log().Warn("Could not load metadata, initializing blank");
_itemTypeNames = new Dictionary<Guid, string>();
_syncPointIndex = new Dictionary<string, Guid>();

persistMetadata();
}
}

void persistMetadata() {
var metadata = new EsentPersistedMetadata() { ItemTypeNames = _itemTypeNames, SyncPointIndex = null };
_backingStore[Guid.Empty] = serializerFactory(metadata).Serialize(metadata);
}
}
}
36 changes: 36 additions & 0 deletions ReactiveXaml.Serialization.Esent/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ReactiveXaml.Serialization.Esent")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("ReactiveXaml.Serialization.Esent")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("0fa075f3-b680-4793-b29b-cde3bfb59c9b")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{0B0ABDC8-4EF3-4172-ADE4-E4FB55E5F91E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ReactiveXaml.Serialization.Esent</RootNamespace>
<AssemblyName>ReactiveXaml.Serialization.Esent</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Esent.Collections">
<HintPath>..\ext\Esent.Collections.dll</HintPath>
</Reference>
<Reference Include="Esent.Interop">
<HintPath>..\ext\Esent.Interop.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="EsentStorageEngine.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ReactiveXaml.Serialization\ReactiveXaml.Serialization.csproj">
<Project>{C6A9A8EC-FDA6-45C1-9694-298D44E3C55F}</Project>
<Name>ReactiveXaml.Serialization</Name>
</ProjectReference>
<ProjectReference Include="..\ReactiveXaml\ReactiveXaml.csproj">
<Project>{292A477B-BB94-43C1-984E-E177EF9FEDB7}</Project>
<Name>ReactiveXaml</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Service References\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
12 changes: 12 additions & 0 deletions ReactiveXaml_Core.sln
Expand Up @@ -18,6 +18,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveXaml.Serialization"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveXaml.Serialization.Tests", "ReactiveXaml.Serialization.Tests\ReactiveXaml.Serialization.Tests.csproj", "{ACA93E36-5301-4F2B-95C8-70897574506B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveXaml.Serialization.Esent", "ReactiveXaml.Serialization.Esent\ReactiveXaml.Serialization.Esent.csproj", "{0B0ABDC8-4EF3-4172-ADE4-E4FB55E5F91E}"
EndProject
Global
GlobalSection(TestCaseManagementSettings) = postSolution
CategoryFile = ReactiveXaml.vsmdi
Expand Down Expand Up @@ -81,6 +83,16 @@ Global
{ACA93E36-5301-4F2B-95C8-70897574506B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{ACA93E36-5301-4F2B-95C8-70897574506B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{ACA93E36-5301-4F2B-95C8-70897574506B}.Release|x86.ActiveCfg = Release|Any CPU
{0B0ABDC8-4EF3-4172-ADE4-E4FB55E5F91E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B0ABDC8-4EF3-4172-ADE4-E4FB55E5F91E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B0ABDC8-4EF3-4172-ADE4-E4FB55E5F91E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{0B0ABDC8-4EF3-4172-ADE4-E4FB55E5F91E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{0B0ABDC8-4EF3-4172-ADE4-E4FB55E5F91E}.Debug|x86.ActiveCfg = Debug|Any CPU
{0B0ABDC8-4EF3-4172-ADE4-E4FB55E5F91E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B0ABDC8-4EF3-4172-ADE4-E4FB55E5F91E}.Release|Any CPU.Build.0 = Release|Any CPU
{0B0ABDC8-4EF3-4172-ADE4-E4FB55E5F91E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{0B0ABDC8-4EF3-4172-ADE4-E4FB55E5F91E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{0B0ABDC8-4EF3-4172-ADE4-E4FB55E5F91E}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down

0 comments on commit 35ef706

Please sign in to comment.