Reworked odb.ng namespace, no Dependencies left to odb, Session management

dev_timestamp
Harald Wolff 2019-08-27 23:40:27 +02:00
parent 5dcb7f60ec
commit 1a7d172ba8
23 changed files with 1445 additions and 441 deletions

2
.gitignore vendored
View File

@ -39,3 +39,5 @@ Thumbs.db
# dotCover # dotCover
*.dotCover *.dotCover
ln.logging

View File

@ -53,7 +53,6 @@
<Compile Include="odb\PreparedObject.cs" /> <Compile Include="odb\PreparedObject.cs" />
<Compile Include="odb\ODBObjectWriter.cs" /> <Compile Include="odb\ODBObjectWriter.cs" />
<Compile Include="odb\ODBFileStorage.cs" /> <Compile Include="odb\ODBFileStorage.cs" />
<Compile Include="odb\Storage.cs" />
<Compile Include="Extensions.cs" /> <Compile Include="Extensions.cs" />
<Compile Include="GeoLocation.cs" /> <Compile Include="GeoLocation.cs" />
<Compile Include="URI.cs" /> <Compile Include="URI.cs" />
@ -121,6 +120,15 @@
<Compile Include="odb\ng\Query.cs" /> <Compile Include="odb\ng\Query.cs" />
<Compile Include="odb\ng\IStorage.cs" /> <Compile Include="odb\ng\IStorage.cs" />
<Compile Include="odb\ng\Document.cs" /> <Compile Include="odb\ng\Document.cs" />
<Compile Include="odb\ng\IStorageContainer.cs" />
<Compile Include="odb\ng\storage\OrganizedFile.cs" />
<Compile Include="odb\ng\storage\OrganizedFileType.cs" />
<Compile Include="odb\ng\storage\FSStorageContainer.cs" />
<Compile Include="odb\ng\storage\FSStorage.cs" />
<Compile Include="odb\ng\storage\StorageAreaContainer.cs" />
<Compile Include="odb\ng\storage\StorageArea.cs" />
<Compile Include="odb\ng\Session.cs" />
<Compile Include="odb\ng\ODBMapper.API.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="sync\" /> <Folder Include="sync\" />
@ -143,7 +151,7 @@
<Folder Include="stream\" /> <Folder Include="stream\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ln.logging\ln.logging.csproj"> <ProjectReference Include="ln.logging\ln.logging.csproj">
<Project>{D471A566-9FB6-41B2-A777-3C32874ECD0E}</Project> <Project>{D471A566-9FB6-41B2-A777-3C32874ECD0E}</Project>
<Name>ln.logging</Name> <Name>ln.logging</Name>
</ProjectReference> </ProjectReference>

29
ln.types.sln 100644
View File

@ -0,0 +1,29 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.types", "ln.types.csproj", "{8D9AB9A5-E513-4BA7-A450-534F6456BF28}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.types.test", "ln.types.test\ln.types.test.csproj", "{E39D8B11-7CF6-4C78-B723-F7E100121704}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.logging", "ln.logging\ln.logging.csproj", "{D471A566-9FB6-41B2-A777-3C32874ECD0E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8D9AB9A5-E513-4BA7-A450-534F6456BF28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8D9AB9A5-E513-4BA7-A450-534F6456BF28}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8D9AB9A5-E513-4BA7-A450-534F6456BF28}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8D9AB9A5-E513-4BA7-A450-534F6456BF28}.Release|Any CPU.Build.0 = Release|Any CPU
{E39D8B11-7CF6-4C78-B723-F7E100121704}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E39D8B11-7CF6-4C78-B723-F7E100121704}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E39D8B11-7CF6-4C78-B723-F7E100121704}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E39D8B11-7CF6-4C78-B723-F7E100121704}.Release|Any CPU.Build.0 = Release|Any CPU
{D471A566-9FB6-41B2-A777-3C32874ECD0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D471A566-9FB6-41B2-A777-3C32874ECD0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D471A566-9FB6-41B2-A777-3C32874ECD0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D471A566-9FB6-41B2-A777-3C32874ECD0E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,90 @@
// /**
// * File: Program.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
using ln.types.odb.ng.storage;
using ln.types.odb.ng;
using ln.logging;
using System.Linq;
namespace ln.types.test
{
class MainClass
{
public static void Main(string[] args)
{
Logger.ConsoleLogger.MaxLogLevel = LogLevel.DEBUGDETAIL;
Logging.Log(LogLevel.DEBUG, "ln.types.odb.ng test suite");
using (IStorageContainer container = new Session(new FSStorageContainer(".")))
{
container.Open();
IStorage storage = container.GetStorage("test");
if (!storage.IsOpen)
storage.Open();
foreach (Guid documentID in storage.GetDocumentIDs())
{
Logging.Log(LogLevel.INFO, "DocumentID: {0}", documentID);
Document doc = storage.Load(documentID);
Logging.Log(LogLevel.INFO, doc.ToString());
doc["FeldC"] = doc["FeldC"].AsLong + 1;
storage.Save(doc);
}
Document document = new Document();
document["FeldA"] = "Ich bin das Feld A";
document["FeldB"] = "Ich bin das Feld B";
document["FeldC"] = new Random().Next();
storage.Save(document);
storage.Save(document);
ODBMapper mapper = new ODBMapper(container);
foreach (MapableClass mapableClass in mapper.GetDocumentIDs<MapableClass>().Select((id)=>mapper.Load<MapableClass>(id)))
{
Logging.Log(LogLevel.INFO, "mapper found: {0}",mapableClass);
mapableClass.ANumber++;
mapper.Save(mapableClass);
}
MapableClass mapable = new MapableClass();
mapper.Save<MapableClass>(mapable);
storage.Close();
container.Close();
}
}
}
class MapableClass
{
public int ANumber { get; set; }
public String MyString;
public MapableClass()
{
ANumber = new Random().Next();
MyString = ANumber.ToString();
}
public override string ToString()
{
return String.Format("[MapableClass ANumber={0} MyString={1}]",ANumber,MyString);
}
}
}

View File

@ -0,0 +1,35 @@
// /**
// * File: AssemblyInfo.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("ln.types.test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E39D8B11-7CF6-4C78-B723-F7E100121704}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>ln.types.test</RootNamespace>
<AssemblyName>ln.types.test</AssemblyName>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ExternalConsole>true</ExternalConsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ExternalConsole>true</ExternalConsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ln.types.csproj">
<Project>{8D9AB9A5-E513-4BA7-A450-534F6456BF28}</Project>
<Name>ln.types</Name>
</ProjectReference>
<ProjectReference Include="..\ln.logging\ln.logging.csproj">
<Project>{D471A566-9FB6-41B2-A777-3C32874ECD0E}</Project>
<Name>ln.logging</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -1,19 +0,0 @@
using System;
namespace ln.types.odb
{
//public abstract class Storage
//{
// public Storage()
// {
// }
// public abstract bool Contains(Guid persistenceID);
// public abstract bool Store(PreparedObject preparedObject);
// public abstract bool Load(PreparedObject preparedObject);
//}
}

View File

@ -10,13 +10,19 @@ namespace ln.types.odb.ng
private Dictionary<ODBValue, ODBValue> properties = new Dictionary<ODBValue, ODBValue>(); private Dictionary<ODBValue, ODBValue> properties = new Dictionary<ODBValue, ODBValue>();
public Document() public Document()
:base(0x1000) :base(0x1001)
{ {
ID = Guid.NewGuid(); ID = Guid.NewGuid();
} }
public Guid ID { get; } public Document(Guid id)
public DateTime StorageTimeStamp { get; private set; } :base(0x1001)
{
ID = id;
}
public Guid ID { get; }
public DateTime StorageTimeStamp { get; set; }
public ODBCollection Collection { get; internal set; } public ODBCollection Collection { get; internal set; }
@ -24,7 +30,7 @@ namespace ln.types.odb.ng
: this(documentID, bytes, 0, bytes.Length) : this(documentID, bytes, 0, bytes.Length)
{ } { }
public Document(Guid documentID,byte[] bytes,int offset,int length) public Document(Guid documentID,byte[] bytes,int offset,int length)
:this() :this(documentID)
{ {
ID = documentID; ID = documentID;
@ -53,9 +59,10 @@ namespace ln.types.odb.ng
} }
set set
{ {
if (ODBNull.Instance.Equals(value) && properties.ContainsKey(propName)) if (ODBNull.Instance.Equals(value))
{ {
properties.Remove(propName); if (properties.ContainsKey(propName))
properties.Remove(propName);
} }
else else
{ {
@ -73,11 +80,22 @@ namespace ln.types.odb.ng
return !ODBNull.Instance.Equals(this[propName]); return !ODBNull.Instance.Equals(this[propName]);
} }
public override byte[] ToStorage() public override ODBValue Clone()
{
Document clone = new Document(ID);
foreach (ODBValue fieldName in properties.Keys)
{
clone[fieldName] = this[fieldName].Clone();
}
return clone;
}
public override byte[] ToStorage()
{ {
MemoryStream stream = new MemoryStream(); MemoryStream stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(stream); BinaryWriter writer = new BinaryWriter(stream);
writer.Write(ID.ToByteArray());
writer.Write(properties.Count); writer.Write(properties.Count);
foreach (ODBValue propName in properties.Keys) foreach (ODBValue propName in properties.Keys)
@ -101,15 +119,15 @@ namespace ln.types.odb.ng
} }
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (obj is ODBDocument) if (obj is Document)
{ {
ODBDocument you = obj as ODBDocument; Document you = obj as Document;
return ID.Equals(you.ID); return ID.Equals(you.ID);
} }
return false; return false;
} }
public bool ContentEquals(ODBDocument other) public bool ContentEquals(Document other)
{ {
if (object.ReferenceEquals(null, other)) if (object.ReferenceEquals(null, other))
return false; return false;
@ -127,10 +145,10 @@ namespace ln.types.odb.ng
public override bool ValueEquals(ODBValue other) public override bool ValueEquals(ODBValue other)
{ {
return ContentEquals(other as ODBDocument); return ContentEquals(other as Document);
} }
public int CompareContent(ODBDocument other) public int CompareContent(Document other)
{ {
ODBValue[] keys = Keys.Union(other.Keys).ToArray(); ODBValue[] keys = Keys.Union(other.Keys).ToArray();
@ -149,11 +167,11 @@ namespace ln.types.odb.ng
public override int CompareInType(ODBValue other) public override int CompareInType(ODBValue other)
{ {
return CompareContent(other as ODBDocument); return CompareContent(other as Document);
} }
public override int CompareValueInType(ODBValue other) public override int CompareValueInType(ODBValue other)
{ {
return CompareContent(other as ODBDocument); return CompareContent(other as Document);
} }
static Document() static Document()

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace ln.types.odb.ng namespace ln.types.odb.ng
{ {
public interface IStorage public interface IStorage
@ -8,8 +9,8 @@ namespace ln.types.odb.ng
void Close(); void Close();
bool IsOpen { get; } bool IsOpen { get; }
ODBDocument Load(Guid documentID); Document Load(Guid documentID);
ODBDocument Save(ODBDocument document); void Save(Document document);
IEnumerable<Guid> GetDocumentIDs(); IEnumerable<Guid> GetDocumentIDs();
} }

View File

@ -0,0 +1,23 @@
// /**
// * File: IStorageContainer.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
using System.Collections.Generic;
namespace ln.types.odb.ng
{
public interface IStorageContainer : IDisposable
{
void Open();
void Close();
bool IsOpen { get; }
IStorage GetStorage(string storageName);
IEnumerable<String> GetStorageNames();
}
}

View File

@ -0,0 +1,88 @@
using ln.types.btree;
using System.Collections.Generic;
using System;
namespace ln.types.odb.ng
{
public partial class ODBMapper
{
BTree<Guid, CachedObject> forwardCache = new BTree<Guid, CachedObject>();
Dictionary<object, CachedObject> reverseCache = new Dictionary<object, CachedObject>();
public T Load<T>(Guid documentID) => (T)Load(typeof(T), documentID);
public object Load(Type type,Guid documentID)
{
lock (this)
{
if (forwardCache.ContainsKey(documentID))
return forwardCache[documentID].Instance;
IStorage storage = StorageContainer.GetStorage(type.FullName);
Document document = storage.Load(documentID);
object instance = ObjectMapping.UnmapValue(this, document);
CachedObject cachedObject = new CachedObject(document, instance);
forwardCache.Add(cachedObject.Document.ID,cachedObject);
reverseCache.Add(cachedObject.Instance, cachedObject);
return cachedObject.Instance;
}
}
public void Save<T>(T instance) => Save(typeof(T), instance);
public void Save(Type type,object instance)
{
lock (this)
{
IStorage storage = StorageContainer.GetStorage(type.FullName);
CachedObject cachedObject;
Document document;
if (reverseCache.ContainsKey(instance))
{
cachedObject = reverseCache[instance];
document = (GetMapping(type) as mappings.ClassMapping).MapDocument(this, cachedObject.Document.ID, instance);
storage.Save(document);
cachedObject.Document = document;
}
else
{
document = (GetMapping(type) as mappings.ClassMapping).MapDocument(this, Guid.NewGuid() ,instance) as Document;
cachedObject = new CachedObject(document, instance);
storage.Save(document);
forwardCache.Add(cachedObject.Document.ID, cachedObject);
reverseCache.Add(instance, cachedObject);
}
}
}
public IEnumerable<Guid> GetDocumentIDs<T>() => GetDocumentIDs(typeof(T));
public IEnumerable<Guid> GetDocumentIDs(Type type)
{
IStorage storage = StorageContainer.GetStorage(type.FullName);
return storage.GetDocumentIDs();
}
struct CachedObject
{
public object Instance;
public Document Document;
public CachedObject(Document document, object instance)
{
Document = document;
Instance = instance;
}
}
}
}

View File

@ -5,6 +5,9 @@ using System.Reflection;
using System.Linq; using System.Linq;
using System.Collections; using System.Collections;
using ln.types.net; using ln.types.net;
using ln.types.odb.ng.storage;
using ln.types.btree;
using ln.types.odb.ng.mappings;
namespace ln.types.odb.ng namespace ln.types.odb.ng
{ {
@ -13,24 +16,24 @@ namespace ln.types.odb.ng
public delegate ODBValue ODBMap<T>(ODBMapper mapper, T value); public delegate ODBValue ODBMap<T>(ODBMapper mapper, T value);
public delegate T ODBUnmap<T>(ODBMapper mapper, ODBValue oval); public delegate T ODBUnmap<T>(ODBMapper mapper, ODBValue oval);
public class ODBMapper public partial class ODBMapper
{ {
public static ODBMapper Default { get; set; } public static ODBMapper Default { get; set; }
public IStorageContainer StorageContainer { get; private set; }
public ODB ODB { get; private set; }
Dictionary<string, ObjectCollection> objectCollections = new Dictionary<string, ObjectCollection>();
Dictionary<Type, IODBMapping> mappings = new Dictionary<Type, IODBMapping>(); Dictionary<Type, IODBMapping> mappings = new Dictionary<Type, IODBMapping>();
mappings.ObjectMapping ObjectMapping { get; }
public ODBMapper(string odbPath) public ODBMapper(string basePath)
:this(new ODB(odbPath)) :this(new FSStorageContainer(basePath))
{ } { }
public ODBMapper(ODB odb) public ODBMapper(IStorageContainer storageContainer)
{ {
if (Default == null) if (Default == null)
Default = this; Default = this;
this.ODB = odb; this.StorageContainer = storageContainer;
RegisterMapping<string>( RegisterMapping<string>(
(mapper, value) => new ODBStringValue(value), (mapper, value) => new ODBStringValue(value),
@ -104,10 +107,11 @@ namespace ln.types.odb.ng
(mapper, oval) => new IPv4(oval.AsUInt) (mapper, oval) => new IPv4(oval.AsUInt)
); );
RegisterMapping(typeof(object),new mappings.ObjectMapping()); ObjectMapping = new mappings.ObjectMapping();
RegisterMapping(typeof(object),ObjectMapping);
} }
public void RegisterMapping(Type nativeType, IODBMapping mapping) public void RegisterMapping(Type nativeType, IODBMapping mapping)
{ {
mappings[nativeType] = mapping; mappings[nativeType] = mapping;
} }
@ -123,20 +127,10 @@ namespace ln.types.odb.ng
); );
} }
public ObjectCollection GetCollection(Type type) => GetCollection(type, type.FullName); public IStorage GetStorage(Type type) => GetStorage(type, type.FullName);
public ObjectCollection GetCollection(Type type,string typeName) public IStorage GetStorage(Type type,string typeName)
{ {
if (!objectCollections.ContainsKey(typeName)) return StorageContainer.GetStorage(typeName);
{
ObjectCollection objectCollection = Activator.CreateInstance(typeof(ObjectCollection<>).MakeGenericType(type),this) as ObjectCollection;
objectCollections[typeName] = objectCollection;
}
return objectCollections[typeName];
}
public ObjectCollection<T> GetCollection<T>() where T : class => GetCollection<T>(typeof(T).FullName);
public ObjectCollection<T> GetCollection<T>(string aliasName) where T:class
{
return GetCollection(typeof(T),aliasName) as ObjectCollection<T>;
} }
public IODBMapping GetMapping<T>() => null; public IODBMapping GetMapping<T>() => null;
@ -184,26 +178,29 @@ namespace ln.types.odb.ng
} }
} }
public object GetDocumentID(object o)
{
IODBMapping mapping = GetMapping(o.GetType());
if (mapping is mappings.ClassMapping) //public object GetDocumentID(object o)
{ //{
mappings.ClassMapping classMapping = mapping as mappings.ClassMapping; // IODBMapping mapping = GetMapping(o.GetType());
return classMapping.getID(o); // if (mapping is mappings.ClassMapping)
} // {
return null; // mappings.ClassMapping classMapping = mapping as mappings.ClassMapping;
} // return classMapping.getID(o);
public Type GetDocumentIDType(Type type) // }
{ // return null;
IODBMapping mapping = GetMapping(type); //}
if (mapping is mappings.ClassMapping) //public Type GetDocumentIDType(Type type)
{ //{
mappings.ClassMapping classMapping = mapping as mappings.ClassMapping; // IODBMapping mapping = GetMapping(type);
return classMapping.IDType; // if (mapping is mappings.ClassMapping)
} // {
return null; // mappings.ClassMapping classMapping = mapping as mappings.ClassMapping;
} // return classMapping.IDType;
// }
// return null;
//}
public virtual ODBValue MapValue(object value) public virtual ODBValue MapValue(object value)
{ {
@ -221,9 +218,9 @@ namespace ln.types.odb.ng
if (ODBNull.Instance.Equals(value)) if (ODBNull.Instance.Equals(value))
return null; return null;
if (value is ODBDocument) if (value is Document)
{ {
ODBDocument doc = value as ODBDocument; Document doc = value as Document;
String asmname = doc["__asm__"].AsString; String asmname = doc["__asm__"].AsString;
String typename = doc["__type__"].AsString; String typename = doc["__type__"].AsString;
@ -270,6 +267,5 @@ namespace ln.types.odb.ng
return null; return null;
return string.Format("{0}, {1}",type.FullName,type.Assembly.GetName().Name); return string.Format("{0}, {1}",type.FullName,type.Assembly.GetName().Name);
} }
}
}
} }

View File

@ -6,303 +6,303 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace ln.types.odb.ng namespace ln.types.odb.ng
{ {
public class ObjectCollection : IEnumerable //public class ObjectCollection : IEnumerable
{ //{
public ODBMapper ODBMapper { get; } // public ODBMapper ODBMapper { get; }
public ODBCollection DocumentCollection { get; private set; } // public ODBCollection DocumentCollection { get; private set; }
public Type ElementType { get; } // public Type ElementType { get; }
public String CollectionName => DocumentCollection.CollectionName; // public String CollectionName => DocumentCollection.CollectionName;
public int Count => DocumentCollection.Count; // public int Count => DocumentCollection.Count;
public Type IDType => ODBMapper.GetDocumentIDType(ElementType); // public Type IDType => ODBMapper.GetDocumentIDType(ElementType);
internal ObjectCollection(ODBMapper odbmapper, Type elementType) // internal ObjectCollection(ODBMapper odbmapper, Type elementType)
: this(odbmapper, elementType, elementType.FullName) // : this(odbmapper, elementType, elementType.FullName)
{ } // { }
internal ObjectCollection(ODBMapper odbmapper, Type elementType, String collectionAlias) // internal ObjectCollection(ODBMapper odbmapper, Type elementType, String collectionAlias)
{ // {
ODBMapper = odbmapper; // ODBMapper = odbmapper;
ElementType = elementType; // ElementType = elementType;
DocumentCollection = ODBMapper.ODB.GetCollection(elementType.FullName); // DocumentCollection = ODBMapper.StorageContainer.GetCollection(elementType.FullName);
} // }
public object SelectByID(object ID) // public object SelectByID(object ID)
{ // {
ODBValue documentID = ODBMapper.MapValue(ID); // ODBValue documentID = ODBMapper.MapValue(ID);
return SelectByID(documentID); // return SelectByID(documentID);
} // }
public object SelectByID(ODBValue documentID) // public object SelectByID(ODBValue documentID)
{ // {
if (ODBNull.Instance.Equals(documentID)) // if (ODBNull.Instance.Equals(documentID))
return null; // return null;
lock (this) // lock (this)
{ // {
object o = GetCachedObject(documentID); // object o = GetCachedObject(documentID);
if (object.ReferenceEquals(null, o)) // if (object.ReferenceEquals(null, o))
{ // {
ODBDocument document = DocumentCollection.GetDocumentByID(documentID); // ODBDocument document = DocumentCollection.GetDocumentByID(documentID);
o = ODBMapper.UnmapValue(ElementType, document); // o = ODBMapper.UnmapValue(ElementType, document);
TouchCache(documentID, o); // TouchCache(documentID, o);
} // }
return o; // return o;
} // }
} // }
public IEnumerable Select(Query query) // public IEnumerable Select(Query query)
{ // {
lock (this) // lock (this)
{ // {
return new ObjectEnumeration(this, query.Execute(DocumentCollection).ToArray()); // return new ObjectEnumeration(this, query.Execute(DocumentCollection).ToArray());
} // }
} // }
public bool Ensure(object o) // public bool Ensure(object o)
{ // {
if (!ElementType.IsInstanceOfType(o)) // if (!ElementType.IsInstanceOfType(o))
throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o)); // throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o));
lock (this) // lock (this)
{ // {
ODBDocument document = ODBMapper.MapValue(o) as ODBDocument; // ODBDocument document = ODBMapper.MapValue(o) as ODBDocument;
if (DocumentCollection.Ensure(document)) // if (DocumentCollection.Ensure(document))
{ // {
TouchCache(document.ID, o); // TouchCache(document.ID, o);
return true; // return true;
} // }
return false; // return false;
} // }
} // }
public bool Insert(object o) // public bool Insert(object o)
{ // {
lock (this) // lock (this)
{ // {
if (!ElementType.IsInstanceOfType(o)) // if (!ElementType.IsInstanceOfType(o))
throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o)); // throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o));
ODBDocument document = ODBMapper.MapValue(o) as ODBDocument; // ODBDocument document = ODBMapper.MapValue(o) as ODBDocument;
if (DocumentCollection.Insert(document)) // if (DocumentCollection.Insert(document))
{ // {
TouchCache(document.ID, o); // TouchCache(document.ID, o);
return true; // return true;
} // }
return false; // return false;
} // }
} // }
public bool Update(object o) // public bool Update(object o)
{ // {
lock (this) // lock (this)
{ // {
lock (this) // lock (this)
{ // {
if (!ElementType.IsInstanceOfType(o)) // if (!ElementType.IsInstanceOfType(o))
throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o)); // throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o));
ODBDocument document = ODBMapper.MapValue(o) as ODBDocument; // ODBDocument document = ODBMapper.MapValue(o) as ODBDocument;
if (DocumentCollection.Update(document)) // if (DocumentCollection.Update(document))
{ // {
TouchCache(document.ID, o); // TouchCache(document.ID, o);
return true; // return true;
} // }
return false; // return false;
} // }
} // }
} // }
public bool Upsert(object o) // public bool Upsert(object o)
{ // {
if (!ElementType.IsInstanceOfType(o)) // if (!ElementType.IsInstanceOfType(o))
throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o)); // throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o));
lock (this) // lock (this)
{ // {
ODBDocument document = ODBMapper.MapValue(o) as ODBDocument; // ODBDocument document = ODBMapper.MapValue(o) as ODBDocument;
if (DocumentCollection.Upsert(document)) // if (DocumentCollection.Upsert(document))
{ // {
TouchCache(document.ID, o); // TouchCache(document.ID, o);
return true; // return true;
} // }
return false; // return false;
} // }
} // }
public bool Delete(object o) => Delete(ODBMapper.MapValue(ODBMapper.GetDocumentID(o))); // public bool Delete(object o) => Delete(ODBMapper.MapValue(ODBMapper.GetDocumentID(o)));
public bool Delete(ODBValue documentID) // public bool Delete(ODBValue documentID)
{ // {
lock (this) // lock (this)
{ // {
if (DocumentCollection.Delete(documentID)) // if (DocumentCollection.Delete(documentID))
{ // {
if (objectCache.ContainsKey(documentID)) // if (objectCache.ContainsKey(documentID))
objectCache.Remove(documentID); // objectCache.Remove(documentID);
return true; // return true;
} // }
return false; // return false;
} // }
} // }
public bool HasProperty(string propName) // public bool HasProperty(string propName)
{ // {
propName = IndexPath.TranslatePropertyPath(ElementType, propName); // propName = IndexPath.TranslatePropertyPath(ElementType, propName);
ClassMapping classMapping = ODBMapper.GetMapping(ElementType) as ClassMapping; // ClassMapping classMapping = ODBMapper.GetMapping(ElementType) as ClassMapping;
if (classMapping != null) // if (classMapping != null)
{ // {
return classMapping.HasField(propName); // return classMapping.HasField(propName);
} // }
return false; // return false;
} // }
/* Indeces */ // /* Indeces */
public void EnsureIndex(string propertyPath, bool unique = false) // public void EnsureIndex(string propertyPath, bool unique = false)
{ // {
//string translatedPath = IndexPath.TranslatePropertyPath(ElementType, propertyPath); // //string translatedPath = IndexPath.TranslatePropertyPath(ElementType, propertyPath);
//DocumentCollection.EnsureIndex(translatedPath, translatedPath); // //DocumentCollection.EnsureIndex(translatedPath, translatedPath);
EnsureIndeces(false, new string[] { propertyPath }); // EnsureIndeces(false, new string[] { propertyPath });
} // }
public void EnsureIndeces(params string[] propertyPaths) => EnsureIndeces(false, propertyPaths); // public void EnsureIndeces(params string[] propertyPaths) => EnsureIndeces(false, propertyPaths);
public void EnsureIndeces(bool unique, params string[] propertyPaths) // public void EnsureIndeces(bool unique, params string[] propertyPaths)
{ // {
for (int n = 0; n < propertyPaths.Length; n++) // for (int n = 0; n < propertyPaths.Length; n++)
propertyPaths[n] = IndexPath.TranslatePropertyPath(ElementType, propertyPaths[n]); // propertyPaths[n] = IndexPath.TranslatePropertyPath(ElementType, propertyPaths[n]);
DocumentCollection.EnsureIndeces(propertyPaths, false); // DocumentCollection.EnsureIndeces(propertyPaths, false);
} // }
public void EnsureUniqueness(params string[] propertyPaths) // public void EnsureUniqueness(params string[] propertyPaths)
{ // {
for (int n = 0; n < propertyPaths.Length; n++) // for (int n = 0; n < propertyPaths.Length; n++)
propertyPaths[n] = IndexPath.TranslatePropertyPath(ElementType, propertyPaths[n]); // propertyPaths[n] = IndexPath.TranslatePropertyPath(ElementType, propertyPaths[n]);
DocumentCollection.EnsureUniqueness(propertyPaths); // DocumentCollection.EnsureUniqueness(propertyPaths);
} // }
/* Object Cache */ // /* Object Cache */
public bool UseStrongCache { get; private set; } // public bool UseStrongCache { get; private set; }
Dictionary<ODBValue, object> objectCache = new Dictionary<ODBValue, object>(); // Dictionary<ODBValue, object> objectCache = new Dictionary<ODBValue, object>();
public void EnableStrongCache(bool enable) // public void EnableStrongCache(bool enable)
{ // {
lock (this) // lock (this)
{ // {
if (!enable) // if (!enable)
{ // {
foreach (ODBValue key in objectCache.Keys.ToArray()) // foreach (ODBValue key in objectCache.Keys.ToArray())
{ // {
if (!(objectCache[key] is WeakReference)) // if (!(objectCache[key] is WeakReference))
objectCache.Remove(key); // objectCache.Remove(key);
} // }
} // }
else // else
{ // {
foreach (ODBValue key in objectCache.Keys.ToArray()) // foreach (ODBValue key in objectCache.Keys.ToArray())
{ // {
if ((objectCache[key] is WeakReference)) // if ((objectCache[key] is WeakReference))
objectCache[key] = (objectCache[key] as WeakReference).Target; // objectCache[key] = (objectCache[key] as WeakReference).Target;
} // }
} // }
} // }
} // }
private object GetCachedObject(ODBValue documentID) // private object GetCachedObject(ODBValue documentID)
{ // {
if (objectCache.ContainsKey(documentID)) // if (objectCache.ContainsKey(documentID))
{ // {
object o = objectCache[documentID]; // object o = objectCache[documentID];
if (o is WeakReference) // if (o is WeakReference)
{ // {
WeakReference weak = o as WeakReference; // WeakReference weak = o as WeakReference;
if (weak.IsAlive) // if (weak.IsAlive)
return weak.Target; // return weak.Target;
else // else
return null; // return null;
} // }
return o; // return o;
} // }
return null; // return null;
} // }
private void TouchCache(ODBValue documentID, object o) // private void TouchCache(ODBValue documentID, object o)
{ // {
if (object.ReferenceEquals(o, null) && objectCache.ContainsKey(documentID)) // if (object.ReferenceEquals(o, null) && objectCache.ContainsKey(documentID))
{ // {
objectCache.Remove(documentID); // objectCache.Remove(documentID);
} // }
else if (!object.ReferenceEquals(o, null)) // else if (!object.ReferenceEquals(o, null))
{ // {
if (UseStrongCache) // if (UseStrongCache)
objectCache[documentID] = o; // objectCache[documentID] = o;
else // else
objectCache[documentID] = new WeakReference(o); // objectCache[documentID] = new WeakReference(o);
} // }
} // }
public object[] GetDocumentIDs() // public object[] GetDocumentIDs()
{ // {
return DocumentCollection.Index.Select((arg) => ODBMapper.UnmapValue(IDType, arg)).ToArray(); // return DocumentCollection.Index.Select((arg) => ODBMapper.UnmapValue(IDType, arg)).ToArray();
} // }
public IEnumerable GetEnumeration() // public IEnumerable GetEnumeration()
{ // {
lock (this) // lock (this)
{ // {
return new ObjectEnumeration(this, DocumentCollection.Index.ToArray()); // return new ObjectEnumeration(this, DocumentCollection.Index.ToArray());
} // }
} // }
public IEnumerator GetEnumerator() // public IEnumerator GetEnumerator()
{ // {
return GetEnumeration().GetEnumerator(); // return GetEnumeration().GetEnumerator();
} // }
public void Close() // public void Close()
{ // {
DocumentCollection = null; // DocumentCollection = null;
} // }
class ObjectEnumeration : IEnumerable // class ObjectEnumeration : IEnumerable
{ // {
ObjectCollection collection; // ObjectCollection collection;
IEnumerable<ODBValue> documentIDs; // IEnumerable<ODBValue> documentIDs;
public ObjectEnumeration(ObjectCollection collection,IEnumerable<ODBValue> documentIDs) // public ObjectEnumeration(ObjectCollection collection,IEnumerable<ODBValue> documentIDs)
{ // {
this.collection = collection; // this.collection = collection;
this.documentIDs = documentIDs; // this.documentIDs = documentIDs;
} // }
public IEnumerator GetEnumerator() // public IEnumerator GetEnumerator()
{ // {
foreach (ODBValue documentID in this.documentIDs) // foreach (ODBValue documentID in this.documentIDs)
{ // {
yield return this.collection.SelectByID(documentID); // yield return this.collection.SelectByID(documentID);
} // }
} // }
} // }
} //}
public class ObjectCollection<T> : ObjectCollection where T:class //public class ObjectCollection<T> : ObjectCollection where T:class
{ //{
public ObjectCollection(ODBMapper odbmapper) // public ObjectCollection(ODBMapper odbmapper)
:base(odbmapper,typeof(T)) // :base(odbmapper,typeof(T))
{} // {}
public IEnumerable<T> SelectQuery(Query query) => base.Select(query).Cast<T>(); // public IEnumerable<T> SelectQuery(Query query) => base.Select(query).Cast<T>();
public T Select(object id) => (T)base.SelectByID(id); // public T Select(object id) => (T)base.SelectByID(id);
public bool Ensure(T o) => base.Ensure(o); // public bool Ensure(T o) => base.Ensure(o);
public bool Insert(T o) => base.Insert(o); // public bool Insert(T o) => base.Insert(o);
public bool Update(T o) => base.Update(o); // public bool Update(T o) => base.Update(o);
public bool Upsert(T o) => base.Upsert(o); // public bool Upsert(T o) => base.Upsert(o);
public void Delete(T o) => base.Delete(o); // public void Delete(T o) => base.Delete(o);
} //}
} }

View File

@ -1,36 +1,36 @@
using System; using System;
namespace ln.types.odb.ng namespace ln.types.odb.ng
{ {
public class Reference<T> where T:class //public class Reference<T> where T:class
{ //{
ODBMapper mapper; // ODBMapper mapper;
ObjectCollection<T> Collection => mapper.GetCollection<T>(); // ObjectCollection<T> Collection => mapper.GetCollection<T>();
internal object valueID; // internal object valueID;
public Reference(ODBMapper mapper) // public Reference(ODBMapper mapper)
{ // {
this.mapper = mapper; // this.mapper = mapper;
} // }
public Reference(ODBMapper mapper,T value) // public Reference(ODBMapper mapper,T value)
{ // {
this.mapper = mapper; // this.mapper = mapper;
this.Value = value; // this.Value = value;
} // }
public T Value // public T Value
{ // {
get // get
{ // {
if (this.valueID == null) // if (this.valueID == null)
return null; // return null;
return this.Collection.Select(valueID); // return this.Collection.Select(valueID);
} // }
set // set
{ // {
this.Collection.Ensure(value); // this.Collection.Ensure(value);
this.valueID = this.mapper.GetDocumentID(value); // this.valueID = this.mapper.GetDocumentID(value);
} // }
} // }
} //}
} }

163
odb/ng/Session.cs 100644
View File

@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using ln.types.odb.values;
using ln.logging;
namespace ln.types.odb.ng
{
public class Session : IStorageContainer
{
public IStorageContainer StorageContainer { get; private set; }
public ODBMapper ODBMapper { get; private set; }
public bool IsOpen => StorageContainer.IsOpen;
public Session(IStorageContainer storageContainer)
{
StorageContainer = storageContainer;
ODBMapper = ODBMapper.Default;
}
private Dictionary<string, IStorage> storages = new Dictionary<string, IStorage>();
public IStorage GetStorage(string storageName)
{
if (storages.ContainsKey(storageName))
return storages[storageName];
IStorage storage = StorageContainer.GetStorage(storageName);
storages.Add(storageName, new SessionCache(storage));
if (!storage.IsOpen)
storage.Open();
return storages[storageName];
}
public void Open()
{
StorageContainer.Open();
}
public void Close()
{
StorageContainer.Close();
}
public IEnumerable<string> GetStorageNames()
{
return StorageContainer.GetStorageNames();
}
public void Dispose()
{
}
class SessionCache : IStorage
{
public IStorage Storage { get; }
public bool IsOpen => Storage.IsOpen;
Dictionary<Guid, CachedDocument> documentCache = new Dictionary<Guid, CachedDocument>();
public SessionCache(IStorage storage)
{
Storage = storage;
}
public bool Open()
{
return Storage.Open();
}
public void Close()
{
Storage.Close();
}
public Document Load(Guid documentID)
{
lock (this)
{
if (!documentCache.ContainsKey(documentID))
{
Document cacheDocument = Storage.Load(documentID);
documentCache.Add(documentID, new CachedDocument(cacheDocument));
}
return documentCache[documentID].WorkingCopy;
}
}
public void Save(Document document)
{
lock (this)
{
if (!documentCache.ContainsKey(document.ID))
{
Logging.Log(LogLevel.DEBUG, "SessionCache: Save(): saving new Document {0}",document.ID);
Storage.Save(document);
documentCache.Add(document.ID, new CachedDocument(document.Clone() as Document,document));
}
else
{
lock (Storage)
{
Document storageDocument = Storage.Load(document.ID);
Document cacheDocument = documentCache[document.ID].CachedCopy;
bool changedFlag = false;
foreach (ODBValue propertyName in document.Keys)
{
if (!document[propertyName].Equals(cacheDocument[propertyName]))
{
Logging.Log(LogLevel.DEBUG, "SessionCache: Save(): found changed field for Document {0}: {1}={2}", document.ID, propertyName, document[propertyName]);
storageDocument[propertyName] = document[propertyName];
changedFlag = true;
}
}
foreach (ODBValue propertyName in cacheDocument.Keys)
{
if (!document.Contains(propertyName))
{
storageDocument[propertyName] = ODBNull.Instance;
changedFlag = true;
}
}
if (changedFlag)
{
Storage.Save(storageDocument);
documentCache[document.ID] = new CachedDocument(document.Clone() as Document,document);
}
else
{
Logging.Log(LogLevel.DEBUG, "SessionCache: Save(): No changes to be saved for document {0}",document.ID);
}
}
}
}
}
public IEnumerable<Guid> GetDocumentIDs()
{
return Storage.GetDocumentIDs();
}
struct CachedDocument
{
public Document CachedCopy;
public Document WorkingCopy;
public CachedDocument(Document cachedCopy)
{
CachedCopy = cachedCopy;
WorkingCopy = cachedCopy.Clone() as Document;
}
public CachedDocument(Document cachedCopy,Document workingCopy)
{
CachedCopy = cachedCopy;
WorkingCopy = workingCopy;
}
}
}
}
}

View File

@ -16,8 +16,8 @@ namespace ln.types.odb.ng.mappings
public Type MappedType { get; } public Type MappedType { get; }
public GetID getID { get; private set; } = (o) => Guid.NewGuid(); //public GetID getID { get; private set; } = (o) => Guid.NewGuid();
public Type IDType { get; private set; } //public Type IDType { get; private set; }
List<FieldInfo> mappedFields = new List<FieldInfo>(); List<FieldInfo> mappedFields = new List<FieldInfo>();
@ -36,20 +36,20 @@ namespace ln.types.odb.ng.mappings
if (fieldinfo.GetCustomAttribute<IgnoreFieldAttribute>() == null) if (fieldinfo.GetCustomAttribute<IgnoreFieldAttribute>() == null)
{ {
mappedFields.Add(fieldinfo); mappedFields.Add(fieldinfo);
if (fieldinfo.GetCustomAttribute<DocumentIDAttribute>() != null) //if (fieldinfo.GetCustomAttribute<DocumentIDAttribute>() != null)
{ //{
getID = (o) => fieldinfo.GetValue(o); // getID = (o) => fieldinfo.GetValue(o);
IDType = fieldinfo.FieldType; // IDType = fieldinfo.FieldType;
} //}
} }
} }
foreach (PropertyInfo propInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) foreach (PropertyInfo propInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{ {
if (propInfo.GetCustomAttribute<DocumentIDAttribute>() != null) //if (propInfo.GetCustomAttribute<DocumentIDAttribute>() != null)
{ //{
getID = (o) => propInfo.GetValue(o); // getID = (o) => propInfo.GetValue(o);
IDType = propInfo.PropertyType; // IDType = propInfo.PropertyType;
} //}
} }
if ((type != null) && !type.IsValueType && (!typeof(object).Equals(type.BaseType))) if ((type != null) && !type.IsValueType && (!typeof(object).Equals(type.BaseType)))
@ -68,7 +68,7 @@ namespace ln.types.odb.ng.mappings
public object UnmapValue(ODBMapper mapper,ODBValue oval) public object UnmapValue(ODBMapper mapper,ODBValue oval)
{ {
ODBDocument document = oval as ODBDocument; Document document = oval as Document;
object o = Activator.CreateInstance(MappedType, true); object o = Activator.CreateInstance(MappedType, true);
foreach (FieldInfo fieldInfo in mappedFields) foreach (FieldInfo fieldInfo in mappedFields)
@ -76,12 +76,13 @@ namespace ln.types.odb.ng.mappings
ByReferenceAttribute byReferenceAttribute = fieldInfo.GetCustomAttribute<ByReferenceAttribute>(); ByReferenceAttribute byReferenceAttribute = fieldInfo.GetCustomAttribute<ByReferenceAttribute>();
if (byReferenceAttribute != null) if (byReferenceAttribute != null)
{ {
Type ceType = byReferenceAttribute.ElementType ?? fieldInfo.FieldType; // ToDo: Implement Referentiel Mapping
String cAlias = byReferenceAttribute.Alias ?? ceType.FullName; //Type ceType = byReferenceAttribute.ElementType ?? fieldInfo.FieldType;
//String cAlias = byReferenceAttribute.Alias ?? ceType.FullName;
ObjectCollection objectCollection = mapper.GetCollection(ceType, cAlias); //ObjectCollection objectCollection = mapper.GetStorage(ceType, cAlias);
ODBValue refID = document[fieldInfo.Name]; //ODBValue refID = document[fieldInfo.Name];
fieldInfo.SetValue(o, objectCollection.SelectByID(refID)); //fieldInfo.SetValue(o, objectCollection.SelectByID(refID));
} }
else else
{ {
@ -104,53 +105,50 @@ namespace ln.types.odb.ng.mappings
return o; return o;
} }
public ODBValue MapValue(ODBMapper mapper,object value) public Document MapDocument(ODBMapper mapper,Guid documentID,object value)
{
Document document = new Document(documentID);
document["__asm__"] = value.GetType().Assembly.GetName().Name;
document["__type__"] = value.GetType().FullName;
foreach (FieldInfo fieldInfo in mappedFields)
{
object fv = fieldInfo.GetValue(value);
ODBValue ov = null;
if (fieldInfo.GetCustomAttribute<ByReferenceAttribute>() != null)
{
if (!object.ReferenceEquals(fv, null))
{
// ToDo: Implement referential mapping
//mapper.GetStorage(fieldInfo.FieldType).Ensure(fv);
//ov = mapper.MapValue(mapper.GetDocumentID(fv));
}
else
ov = ODBNull.Instance;
}
else
{
ov = mapper.MapValue(fv);
}
document[fieldInfo.Name] = ov;
}
return document;
}
public ODBValue MapValue(ODBMapper mapper,object value)
{ {
if (Object.ReferenceEquals(value, null)) if (Object.ReferenceEquals(value, null))
return ODBNull.Instance; return ODBNull.Instance;
ODBDocument document = new ODBDocument(); return MapDocument(mapper, Guid.Empty, value);
document["__asm__"] = value.GetType().Assembly.GetName().Name;
document["__type__"] = value.GetType().FullName;
foreach (FieldInfo fieldInfo in mappedFields)
{
object fv = fieldInfo.GetValue(value);
ODBValue ov = null;
if (fieldInfo.GetCustomAttribute<ByReferenceAttribute>() != null)
{
if (!object.ReferenceEquals(fv, null))
{
mapper.GetCollection(fieldInfo.FieldType).Ensure(fv);
ov = mapper.MapValue(mapper.GetDocumentID(fv));
}
else
ov = ODBNull.Instance;
}
else
{
ov = mapper.MapValue(fv);
}
document[fieldInfo.Name] = ov;
}
document.ID = mapper.MapValue(getID(value));
return document;
} }
public Type GetFieldType(ODBMapper mapper,string fieldName) public Type GetFieldType(ODBMapper mapper,string fieldName)
{ {
foreach (FieldInfo fieldInfo in mappedFields) foreach (FieldInfo fieldInfo in mappedFields)
if (fieldInfo.Name.Equals(fieldName)) if (fieldInfo.Name.Equals(fieldName))
if (fieldInfo.GetCustomAttribute<ByReferenceAttribute>() != null) return fieldInfo.FieldType;
{
return mapper.GetDocumentIDType(fieldInfo.FieldType);
} else
{
return fieldInfo.FieldType;
}
throw new KeyNotFoundException(); throw new KeyNotFoundException();
} }
@ -162,14 +160,14 @@ namespace ln.types.odb.ng.mappings
public ODBValue MapValue(ODBMapper mapper, object value) public ODBValue MapValue(ODBMapper mapper, object value)
{ {
return new ODBDocument(); return new Document();
} }
public object UnmapValue(ODBMapper mapper, ODBValue oval) public object UnmapValue(ODBMapper mapper, ODBValue oval)
{ {
if (oval is ODBDocument) if (oval is Document)
{ {
ODBDocument document = oval.AsDocument; Document document = oval as Document;
if (!document.Contains("__type__")) if (!document.Contains("__type__"))
return new object(); return new object();

View File

@ -20,13 +20,13 @@ namespace ln.types.odb.ng.mappings
if (dType.GetInterfaces().Contains(typeof(IDictionary))) if (dType.GetInterfaces().Contains(typeof(IDictionary)))
{ {
IDictionary dictionary = value as IDictionary; IDictionary dictionary = value as IDictionary;
ODBDocument document = new ODBDocument(); Document document = new Document();
document["__asm__"] = value.GetType().Assembly.GetName().Name; document["__asm__"] = value.GetType().Assembly.GetName().Name;
document["__type__"] = value.GetType().FullName; document["__type__"] = value.GetType().FullName;
ODBDocument kTypes = new ODBDocument(); Document kTypes = new Document();
ODBDocument vTypes = new ODBDocument(); Document vTypes = new Document();
document["__ktypes__"] = kTypes; document["__ktypes__"] = kTypes;
document["__vtypes__"] = vTypes; document["__vtypes__"] = vTypes;
@ -47,7 +47,7 @@ namespace ln.types.odb.ng.mappings
public object UnmapValue(ODBMapper mapper, ODBValue oval) public object UnmapValue(ODBMapper mapper, ODBValue oval)
{ {
ODBDocument document = oval.AsDocument; Document document = oval as Document;
Type dType = Type.GetType(String.Format("{0}, {1}",document["__type__"].AsString,document["__asm__"].AsString)); //;Assembly.Load(document["__asm__"].AsString).GetType(document["__type__"].AsString); Type dType = Type.GetType(String.Format("{0}, {1}",document["__type__"].AsString,document["__asm__"].AsString)); //;Assembly.Load(document["__asm__"].AsString).GetType(document["__type__"].AsString);
if (dType.IsGenericType) if (dType.IsGenericType)
@ -59,8 +59,8 @@ namespace ln.types.odb.ng.mappings
Type kType = dType.GetGenericArguments()[0]; Type kType = dType.GetGenericArguments()[0];
Type vType = dType.GetGenericArguments()[1]; Type vType = dType.GetGenericArguments()[1];
ODBDocument ktypes = document.Contains("__ktypes__") ? document["__ktypes__"].AsDocument : new ODBDocument(); Document ktypes = document.Contains("__ktypes__") ? document["__ktypes__"] as Document : new Document();
ODBDocument vtypes = document.Contains("__vtypes__") ? document["__vtypes__"].AsDocument : new ODBDocument(); Document vtypes = document.Contains("__vtypes__") ? document["__vtypes__"] as Document : new Document();
foreach (ODBValue key in document.Keys) foreach (ODBValue key in document.Keys)
{ {

View File

@ -0,0 +1,292 @@
// /**
// * File: FSSTorage.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization.Advanced;
using ln.logging;
namespace ln.types.odb.ng.storage
{
/**
* FSStorage
*
* Directory Layout:
*
* <BasePath>/<StorageName>
* /data.odb Serialized Document Data
* /data.idx Serialized Lookup Index for Documents and Free Areas
*
* data.odb
* ----------
* 0000 4 MAGIC Bytes
* 0004 4 Version
* 0008 8 LastCloseTimestamp
* 0010 4 FirstOffset
* 0014 4 GranularWidth
* 0018 8 Reserved 0
*
**/
public class FSStorage : IStorage
{
public byte[] MagicBytes { get; } = new byte[] { 0x0F, 0x0E, 0x0D, 0x0A };
public String StoragePath { get; }
public String StorageName { get; }
public int FileVersion { get; private set; }
public long LastCloseTimestamp { get; private set; }
public int FirstOffset { get; private set; }
public int GranularWidth { get; private set; } = 12;
public int GranularityMask => (1 << GranularWidth) - 1;
public int AppendOffset { get; private set; }
StorageAreaContainer storageAreas = new StorageAreaContainer();
Dictionary<Guid, StorageArea> documentAreas = new Dictionary<Guid, StorageArea>();
FileStream fileStream;
public FSStorage(string storagePath)
{
StoragePath = storagePath;
StorageName = Path.GetFileName(storagePath);
}
public FSStorage(string storagePath,int granularWidth)
:this(storagePath)
{
GranularWidth = granularWidth;
}
private void AssertOpen()
{
if (fileStream == null)
throw new IOException("FSStorage not opened");
}
public bool IsOpen => (fileStream != null);
public bool Open()
{
if (!IsOpen)
{
try
{
if (!Directory.Exists(StoragePath))
Directory.CreateDirectory(StoragePath);
fileStream = new FileStream(Path.Combine(StoragePath, "data.odb"), FileMode.OpenOrCreate);
if (fileStream.Length == 0)
{
FileVersion = 0;
LastCloseTimestamp = 0;
FirstOffset = (1 << GranularWidth);
if (FirstOffset < 0x20)
throw new NotSupportedException("Granularity too small");
AppendOffset = FirstOffset;
Close();
return Open();
}
else
{
if (!fileStream.ReadBytes(4).SequenceEqual(MagicBytes))
throw new IOException("Magic bytes do not match");
FileVersion = fileStream.ReadInteger();
LastCloseTimestamp = fileStream.ReadLong();
FirstOffset = fileStream.ReadInteger();
GranularWidth = fileStream.ReadInteger();
Scan();
}
}
catch (Exception e)
{
Logging.Log(e);
if (fileStream != null)
{
fileStream.Close();
fileStream.Dispose();
fileStream = null;
}
return false;
}
return true;
}
return false;
}
private void Scan()
{
int offset = FirstOffset;
while (offset < fileStream.Length)
{
fileStream.Position = offset;
StorageArea storageArea = new StorageArea(offset, fileStream.ReadInteger());
Guid documentID = new Guid(fileStream.ReadBytes(16));
if (Guid.Empty.Equals(documentID))
storageAreas.Push(storageArea);
else
{
if (documentAreas.ContainsKey(documentID))
{
Document previousDoc = LoadDocument(documentAreas[documentID]);
Document currentDoc = LoadDocument(storageArea);
if (previousDoc.StorageTimeStamp < currentDoc.StorageTimeStamp)
{
WriteStorageArea(documentAreas[documentID]);
storageAreas.Push(documentAreas[documentID]);
documentAreas[documentID] = storageArea;
}
else
{
WriteStorageArea(storageArea);
storageAreas.Push(storageArea);
}
} else
{
documentAreas.Add(documentID, storageArea);
}
}
offset = storageArea.NextOffset;
}
AppendOffset = offset;
}
public void Close()
{
lock (this){
AssertOpen();
fileStream.Position = 0;
fileStream.WriteBytes(MagicBytes);
fileStream.WriteInteger(FileVersion);
LastCloseTimestamp = (long)DateTime.Now.ToUnixTimeMilliseconds();
fileStream.WriteLong(LastCloseTimestamp);
fileStream.WriteInteger(FirstOffset);
fileStream.WriteInteger(GranularWidth);
fileStream.Close();
fileStream.Dispose();
fileStream = null;
}
}
public IEnumerable<Guid> GetDocumentIDs()
{
lock (this)
{
return documentAreas.Keys.ToArray();
}
}
public Document Load(Guid documentID)
{
lock (this)
{
if (!documentAreas.ContainsKey(documentID))
throw new KeyNotFoundException();
StorageArea storageArea = documentAreas[documentID];
return LoadDocument(storageArea);
}
}
private Document LoadDocument(StorageArea storageArea)
{
fileStream.Position = storageArea.Offset + 4;
Guid documentID = new Guid(fileStream.ReadBytes(16));
byte[] storageBytes = fileStream.ReadBytes(storageArea.Size - 20);
return new Document(documentID, storageBytes);
}
public void Save(Document document)
{
lock (this)
{
document.StorageTimeStamp = DateTime.Now;
byte[] storageBytes = document.ToStorage();
StorageArea storageArea = storageAreas.Pop(storageBytes.Length + 20);
if (storageArea == null)
storageArea = AppendStorageArea(storageBytes.Length + 20);
int neededSize = storageBytes.Length + 20;
CheckGranularity(ref neededSize);
if (storageArea.Size > neededSize)
{
StorageArea splitArea = storageArea.Split(storageArea.Size - neededSize);
WriteStorageArea(splitArea);
}
WriteStorageArea(storageArea, storageBytes);
if (documentAreas.ContainsKey(document.ID))
{
StorageArea oldStorageArea = documentAreas[document.ID];
WriteStorageArea(oldStorageArea);
storageAreas.Push(oldStorageArea);
}
documentAreas[document.ID] = storageArea;
}
}
public void Delete(Guid documentID)
{
lock (this)
{
if (documentAreas.ContainsKey(documentID))
{
StorageArea storageArea = documentAreas[documentID];
documentAreas.Remove(documentID);
storageArea = storageAreas.Push(storageArea);
WriteStorageArea(storageArea);
}
}
}
private StorageArea AppendStorageArea(int size)
{
CheckGranularity(ref size);
return new StorageArea(AppendOffset, size);
}
private void WriteStorageArea(StorageArea storageArea) => WriteStorageArea(storageArea, new byte[0]);
private void WriteStorageArea(StorageArea storageArea,byte[] data)
{
AssertOpen();
if (data.Length > (storageArea.Size - 4))
throw new ArgumentOutOfRangeException(nameof(data));
fileStream.Position = storageArea.Offset;
fileStream.WriteInteger(storageArea.Size);
fileStream.WriteBytes(data);
fileStream.WriteBytes(new byte[ storageArea.Size - 4 - data.Length]);
}
private void CheckGranularity(ref int i)
{
i = (i + GranularityMask) & ~GranularityMask;
}
}
}

View File

@ -0,0 +1,97 @@
// /**
// * File: FSStorage.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ln.types.odb.ng.storage
{
public class FSStorageContainer : IStorageContainer,IDisposable
{
public string BasePath { get; }
FileStream lockFile;
Dictionary<string, FSStorage> storages = new Dictionary<string, FSStorage>();
public FSStorageContainer(string basePath)
{
BasePath = basePath;
}
public bool IsOpen => lockFile != null;
private void AssertOpen()
{
if (!IsOpen)
throw new IOException("FSSTorage not open");
}
public void Close()
{
lock (this)
{
AssertOpen();
if (lockFile != null)
{
lockFile.Close();
lockFile.Dispose();
lockFile = null;
}
}
}
public IStorage GetStorage(string storageName)
{
lock (this)
{
AssertOpen();
if (!storages.ContainsKey(storageName))
storages.Add(storageName, new FSStorage(Path.Combine(BasePath, storageName)));
return storages[storageName];
}
}
public IEnumerable<string> GetStorageNames()
{
lock (this)
{
AssertOpen();
return storages.Keys;
}
}
public void Open()
{
lock (this)
{
if (!IsOpen)
{
if (!Directory.Exists(BasePath))
Directory.CreateDirectory(BasePath);
lockFile = new FileStream(Path.Combine(BasePath, ".lock"), FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None, 1024, FileOptions.DeleteOnClose);
foreach (String storagePath in Directory.EnumerateDirectories(BasePath))
{
FSStorage storage = new FSStorage(storagePath);
storages.Add(storage.StorageName, storage);
}
}
}
}
public void Dispose()
{
if (IsOpen)
Close();
}
}
}

View File

@ -0,0 +1,38 @@
// /**
// * File: StorageArea.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
namespace ln.types.odb.ng.storage
{
public class StorageArea
{
public int Offset { get; }
public int Size { get; set; }
public int NextOffset => Offset + Size;
public StorageArea(int offset,int size)
{
Offset = offset;
Size = size;
}
public StorageArea Split(int splitSize)
{
if (splitSize >= Size)
throw new ArgumentOutOfRangeException(nameof(splitSize));
StorageArea splitArea = new StorageArea(Offset + Size - splitSize,splitSize);
Size -= splitSize;
return splitArea;
}
}
}

View File

@ -0,0 +1,69 @@
// /**
// * File: StorageAreaContainer.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
using ln.types.btree;
namespace ln.types.odb.ng.storage
{
public class StorageAreaContainer
{
public int SplitLimit { get; set; } = 32;
MappingBTree<int, StorageArea> storageAreas = new MappingBTree<int, StorageArea>((value)=>value.Offset);
public StorageAreaContainer()
{
}
public StorageArea Push(StorageArea storageArea)
{
storageAreas.Add(storageArea);
try
{
StorageArea previousStorageArea = storageAreas.Previous(storageArea);
if ((previousStorageArea != null) && (previousStorageArea.NextOffset == storageArea.Offset))
{
previousStorageArea.Size += storageArea.Size;
storageAreas.Remove(storageArea);
storageArea = previousStorageArea;
}
} catch
{
}
try
{
StorageArea nextStorageArea = storageAreas.Next(storageArea);
if ((nextStorageArea != null) && (storageArea.NextOffset == nextStorageArea.Offset))
{
storageArea.Size += nextStorageArea.Size;
storageAreas.Remove(nextStorageArea);
}
} catch
{ }
return storageArea;
}
public StorageArea Pop(int minSize)
{
foreach (StorageArea storageArea in storageAreas)
{
if (storageArea.Size >= minSize)
{
storageAreas.RemoveKey(storageArea.Offset);
return storageArea;
}
}
return null;
}
}
}

View File

@ -43,7 +43,14 @@ namespace ln.types.odb.values
public int Count => items.Count; public int Count => items.Count;
public override object Value { public override ODBValue Clone()
{
ODBList clone = new ODBList();
clone.items.AddRange(this.items);
return clone;
}
public override object Value {
get get
{ {
object[] a = new object[items.Count]; object[] a = new object[items.Count];

View File

@ -94,7 +94,13 @@ namespace ln.types.odb.values
public virtual ODBDocument AsDocument => (ODBDocument)this; public virtual ODBDocument AsDocument => (ODBDocument)this;
public virtual void Store(BinaryWriter storage) public virtual ODBValue Clone()
{
return this;
}
public virtual void Store(BinaryWriter storage)
{ {
byte[] storageBytes = ToStorage(); byte[] storageBytes = ToStorage();
@ -221,5 +227,21 @@ namespace ln.types.odb.values
{ {
return a.CompareValueTo(b); return a.CompareValueTo(b);
} }
}
static ODBValue()
{
new ODBDocument();
new ODBNull();
new ODBStringValue();
new ODBBool();
new ODBList();
new ODBInteger();
new ODBUInteger();
new ODBLong();
new ODBULong();
new ODBDouble();
new ODBGuid();
new ODBTypedValue();
}
}
} }