Reworked odb.ng namespace, no Dependencies left to odb, Session management
parent
5dcb7f60ec
commit
1a7d172ba8
|
@ -39,3 +39,5 @@ Thumbs.db
|
|||
|
||||
# dotCover
|
||||
*.dotCover
|
||||
|
||||
ln.logging
|
|
@ -53,7 +53,6 @@
|
|||
<Compile Include="odb\PreparedObject.cs" />
|
||||
<Compile Include="odb\ODBObjectWriter.cs" />
|
||||
<Compile Include="odb\ODBFileStorage.cs" />
|
||||
<Compile Include="odb\Storage.cs" />
|
||||
<Compile Include="Extensions.cs" />
|
||||
<Compile Include="GeoLocation.cs" />
|
||||
<Compile Include="URI.cs" />
|
||||
|
@ -121,6 +120,15 @@
|
|||
<Compile Include="odb\ng\Query.cs" />
|
||||
<Compile Include="odb\ng\IStorage.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>
|
||||
<Folder Include="sync\" />
|
||||
|
@ -143,7 +151,7 @@
|
|||
<Folder Include="stream\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ln.logging\ln.logging.csproj">
|
||||
<ProjectReference Include="ln.logging\ln.logging.csproj">
|
||||
<Project>{D471A566-9FB6-41B2-A777-3C32874ECD0E}</Project>
|
||||
<Name>ln.logging</Name>
|
||||
</ProjectReference>
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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("")]
|
|
@ -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>
|
|
@ -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);
|
||||
|
||||
|
||||
|
||||
//}
|
||||
}
|
|
@ -10,13 +10,19 @@ namespace ln.types.odb.ng
|
|||
private Dictionary<ODBValue, ODBValue> properties = new Dictionary<ODBValue, ODBValue>();
|
||||
|
||||
public Document()
|
||||
:base(0x1000)
|
||||
:base(0x1001)
|
||||
{
|
||||
ID = Guid.NewGuid();
|
||||
ID = Guid.NewGuid();
|
||||
}
|
||||
|
||||
public Guid ID { get; }
|
||||
public DateTime StorageTimeStamp { get; private set; }
|
||||
public Document(Guid id)
|
||||
:base(0x1001)
|
||||
{
|
||||
ID = id;
|
||||
}
|
||||
|
||||
public Guid ID { get; }
|
||||
public DateTime StorageTimeStamp { get; set; }
|
||||
|
||||
public ODBCollection Collection { get; internal set; }
|
||||
|
||||
|
@ -24,7 +30,7 @@ namespace ln.types.odb.ng
|
|||
: this(documentID, bytes, 0, bytes.Length)
|
||||
{ }
|
||||
public Document(Guid documentID,byte[] bytes,int offset,int length)
|
||||
:this()
|
||||
:this(documentID)
|
||||
{
|
||||
ID = documentID;
|
||||
|
||||
|
@ -53,9 +59,10 @@ namespace ln.types.odb.ng
|
|||
}
|
||||
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
|
||||
{
|
||||
|
@ -73,11 +80,22 @@ namespace ln.types.odb.ng
|
|||
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();
|
||||
BinaryWriter writer = new BinaryWriter(stream);
|
||||
|
||||
writer.Write(ID.ToByteArray());
|
||||
writer.Write(properties.Count);
|
||||
|
||||
foreach (ODBValue propName in properties.Keys)
|
||||
|
@ -101,15 +119,15 @@ namespace ln.types.odb.ng
|
|||
}
|
||||
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 false;
|
||||
}
|
||||
|
||||
public bool ContentEquals(ODBDocument other)
|
||||
public bool ContentEquals(Document other)
|
||||
{
|
||||
if (object.ReferenceEquals(null, other))
|
||||
return false;
|
||||
|
@ -127,10 +145,10 @@ namespace ln.types.odb.ng
|
|||
|
||||
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();
|
||||
|
||||
|
@ -149,11 +167,11 @@ namespace ln.types.odb.ng
|
|||
|
||||
public override int CompareInType(ODBValue other)
|
||||
{
|
||||
return CompareContent(other as ODBDocument);
|
||||
return CompareContent(other as Document);
|
||||
}
|
||||
public override int CompareValueInType(ODBValue other)
|
||||
{
|
||||
return CompareContent(other as ODBDocument);
|
||||
return CompareContent(other as Document);
|
||||
}
|
||||
|
||||
static Document()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ln.types.odb.ng
|
||||
{
|
||||
public interface IStorage
|
||||
|
@ -8,8 +9,8 @@ namespace ln.types.odb.ng
|
|||
void Close();
|
||||
bool IsOpen { get; }
|
||||
|
||||
ODBDocument Load(Guid documentID);
|
||||
ODBDocument Save(ODBDocument document);
|
||||
Document Load(Guid documentID);
|
||||
void Save(Document document);
|
||||
|
||||
IEnumerable<Guid> GetDocumentIDs();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -5,6 +5,9 @@ using System.Reflection;
|
|||
using System.Linq;
|
||||
using System.Collections;
|
||||
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
|
||||
{
|
||||
|
@ -13,24 +16,24 @@ namespace ln.types.odb.ng
|
|||
public delegate ODBValue ODBMap<T>(ODBMapper mapper, T value);
|
||||
public delegate T ODBUnmap<T>(ODBMapper mapper, ODBValue oval);
|
||||
|
||||
public class ODBMapper
|
||||
public partial class ODBMapper
|
||||
{
|
||||
public static ODBMapper Default { get; set; }
|
||||
|
||||
public ODB ODB { get; private set; }
|
||||
|
||||
Dictionary<string, ObjectCollection> objectCollections = new Dictionary<string, ObjectCollection>();
|
||||
public IStorageContainer StorageContainer { get; private set; }
|
||||
|
||||
Dictionary<Type, IODBMapping> mappings = new Dictionary<Type, IODBMapping>();
|
||||
|
||||
mappings.ObjectMapping ObjectMapping { get; }
|
||||
|
||||
public ODBMapper(string odbPath)
|
||||
:this(new ODB(odbPath))
|
||||
public ODBMapper(string basePath)
|
||||
:this(new FSStorageContainer(basePath))
|
||||
{ }
|
||||
public ODBMapper(ODB odb)
|
||||
public ODBMapper(IStorageContainer storageContainer)
|
||||
{
|
||||
if (Default == null)
|
||||
Default = this;
|
||||
|
||||
this.ODB = odb;
|
||||
this.StorageContainer = storageContainer;
|
||||
|
||||
RegisterMapping<string>(
|
||||
(mapper, value) => new ODBStringValue(value),
|
||||
|
@ -104,10 +107,11 @@ namespace ln.types.odb.ng
|
|||
(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;
|
||||
}
|
||||
|
@ -123,20 +127,10 @@ namespace ln.types.odb.ng
|
|||
);
|
||||
}
|
||||
|
||||
public ObjectCollection GetCollection(Type type) => GetCollection(type, type.FullName);
|
||||
public ObjectCollection GetCollection(Type type,string typeName)
|
||||
public IStorage GetStorage(Type type) => GetStorage(type, type.FullName);
|
||||
public IStorage GetStorage(Type type,string typeName)
|
||||
{
|
||||
if (!objectCollections.ContainsKey(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>;
|
||||
return StorageContainer.GetStorage(typeName);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
mappings.ClassMapping classMapping = mapping as mappings.ClassMapping;
|
||||
return classMapping.getID(o);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Type GetDocumentIDType(Type type)
|
||||
{
|
||||
IODBMapping mapping = GetMapping(type);
|
||||
if (mapping is mappings.ClassMapping)
|
||||
{
|
||||
mappings.ClassMapping classMapping = mapping as mappings.ClassMapping;
|
||||
return classMapping.IDType;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//public object GetDocumentID(object o)
|
||||
//{
|
||||
// IODBMapping mapping = GetMapping(o.GetType());
|
||||
// if (mapping is mappings.ClassMapping)
|
||||
// {
|
||||
// mappings.ClassMapping classMapping = mapping as mappings.ClassMapping;
|
||||
// return classMapping.getID(o);
|
||||
// }
|
||||
// return null;
|
||||
//}
|
||||
//public Type GetDocumentIDType(Type type)
|
||||
//{
|
||||
// IODBMapping mapping = GetMapping(type);
|
||||
// if (mapping is mappings.ClassMapping)
|
||||
// {
|
||||
// mappings.ClassMapping classMapping = mapping as mappings.ClassMapping;
|
||||
// return classMapping.IDType;
|
||||
// }
|
||||
// return null;
|
||||
//}
|
||||
|
||||
public virtual ODBValue MapValue(object value)
|
||||
{
|
||||
|
@ -221,9 +218,9 @@ namespace ln.types.odb.ng
|
|||
if (ODBNull.Instance.Equals(value))
|
||||
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 typename = doc["__type__"].AsString;
|
||||
|
||||
|
@ -270,6 +267,5 @@ namespace ln.types.odb.ng
|
|||
return null;
|
||||
return string.Format("{0}, {1}",type.FullName,type.Assembly.GetName().Name);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,303 +6,303 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
namespace ln.types.odb.ng
|
||||
{
|
||||
public class ObjectCollection : IEnumerable
|
||||
{
|
||||
public ODBMapper ODBMapper { get; }
|
||||
public ODBCollection DocumentCollection { get; private set; }
|
||||
//public class ObjectCollection : IEnumerable
|
||||
//{
|
||||
// public ODBMapper ODBMapper { get; }
|
||||
// public ODBCollection DocumentCollection { get; private set; }
|
||||
|
||||
public Type ElementType { get; }
|
||||
public String CollectionName => DocumentCollection.CollectionName;
|
||||
// public Type ElementType { get; }
|
||||
// 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)
|
||||
: this(odbmapper, elementType, elementType.FullName)
|
||||
{ }
|
||||
internal ObjectCollection(ODBMapper odbmapper, Type elementType, String collectionAlias)
|
||||
{
|
||||
ODBMapper = odbmapper;
|
||||
ElementType = elementType;
|
||||
DocumentCollection = ODBMapper.ODB.GetCollection(elementType.FullName);
|
||||
}
|
||||
// internal ObjectCollection(ODBMapper odbmapper, Type elementType)
|
||||
// : this(odbmapper, elementType, elementType.FullName)
|
||||
// { }
|
||||
// internal ObjectCollection(ODBMapper odbmapper, Type elementType, String collectionAlias)
|
||||
// {
|
||||
// ODBMapper = odbmapper;
|
||||
// ElementType = elementType;
|
||||
// DocumentCollection = ODBMapper.StorageContainer.GetCollection(elementType.FullName);
|
||||
// }
|
||||
|
||||
public object SelectByID(object ID)
|
||||
{
|
||||
ODBValue documentID = ODBMapper.MapValue(ID);
|
||||
return SelectByID(documentID);
|
||||
}
|
||||
public object SelectByID(ODBValue documentID)
|
||||
{
|
||||
if (ODBNull.Instance.Equals(documentID))
|
||||
return null;
|
||||
lock (this)
|
||||
{
|
||||
object o = GetCachedObject(documentID);
|
||||
if (object.ReferenceEquals(null, o))
|
||||
{
|
||||
ODBDocument document = DocumentCollection.GetDocumentByID(documentID);
|
||||
o = ODBMapper.UnmapValue(ElementType, document);
|
||||
TouchCache(documentID, o);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
}
|
||||
// public object SelectByID(object ID)
|
||||
// {
|
||||
// ODBValue documentID = ODBMapper.MapValue(ID);
|
||||
// return SelectByID(documentID);
|
||||
// }
|
||||
// public object SelectByID(ODBValue documentID)
|
||||
// {
|
||||
// if (ODBNull.Instance.Equals(documentID))
|
||||
// return null;
|
||||
// lock (this)
|
||||
// {
|
||||
// object o = GetCachedObject(documentID);
|
||||
// if (object.ReferenceEquals(null, o))
|
||||
// {
|
||||
// ODBDocument document = DocumentCollection.GetDocumentByID(documentID);
|
||||
// o = ODBMapper.UnmapValue(ElementType, document);
|
||||
// TouchCache(documentID, o);
|
||||
// }
|
||||
// return o;
|
||||
// }
|
||||
// }
|
||||
|
||||
public IEnumerable Select(Query query)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
return new ObjectEnumeration(this, query.Execute(DocumentCollection).ToArray());
|
||||
}
|
||||
}
|
||||
// public IEnumerable Select(Query query)
|
||||
// {
|
||||
// lock (this)
|
||||
// {
|
||||
// return new ObjectEnumeration(this, query.Execute(DocumentCollection).ToArray());
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
public bool Ensure(object o)
|
||||
{
|
||||
if (!ElementType.IsInstanceOfType(o))
|
||||
throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o));
|
||||
// public bool Ensure(object o)
|
||||
// {
|
||||
// if (!ElementType.IsInstanceOfType(o))
|
||||
// throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o));
|
||||
|
||||
lock (this)
|
||||
{
|
||||
ODBDocument document = ODBMapper.MapValue(o) as ODBDocument;
|
||||
if (DocumentCollection.Ensure(document))
|
||||
{
|
||||
TouchCache(document.ID, o);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// lock (this)
|
||||
// {
|
||||
// ODBDocument document = ODBMapper.MapValue(o) as ODBDocument;
|
||||
// if (DocumentCollection.Ensure(document))
|
||||
// {
|
||||
// TouchCache(document.ID, o);
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
public bool Insert(object o)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (!ElementType.IsInstanceOfType(o))
|
||||
throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o));
|
||||
// public bool Insert(object o)
|
||||
// {
|
||||
// lock (this)
|
||||
// {
|
||||
// if (!ElementType.IsInstanceOfType(o))
|
||||
// throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o));
|
||||
|
||||
ODBDocument document = ODBMapper.MapValue(o) as ODBDocument;
|
||||
if (DocumentCollection.Insert(document))
|
||||
{
|
||||
TouchCache(document.ID, o);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool Update(object o)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (!ElementType.IsInstanceOfType(o))
|
||||
throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o));
|
||||
// ODBDocument document = ODBMapper.MapValue(o) as ODBDocument;
|
||||
// if (DocumentCollection.Insert(document))
|
||||
// {
|
||||
// TouchCache(document.ID, o);
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// public bool Update(object o)
|
||||
// {
|
||||
// lock (this)
|
||||
// {
|
||||
// lock (this)
|
||||
// {
|
||||
// if (!ElementType.IsInstanceOfType(o))
|
||||
// throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o));
|
||||
|
||||
ODBDocument document = ODBMapper.MapValue(o) as ODBDocument;
|
||||
if (DocumentCollection.Update(document))
|
||||
{
|
||||
TouchCache(document.ID, o);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool Upsert(object o)
|
||||
{
|
||||
if (!ElementType.IsInstanceOfType(o))
|
||||
throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o));
|
||||
// ODBDocument document = ODBMapper.MapValue(o) as ODBDocument;
|
||||
// if (DocumentCollection.Update(document))
|
||||
// {
|
||||
// TouchCache(document.ID, o);
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// public bool Upsert(object o)
|
||||
// {
|
||||
// if (!ElementType.IsInstanceOfType(o))
|
||||
// throw new ArgumentException(String.Format("Object needs to be of type {0}", ElementType.FullName), nameof(o));
|
||||
|
||||
lock (this)
|
||||
{
|
||||
ODBDocument document = ODBMapper.MapValue(o) as ODBDocument;
|
||||
if (DocumentCollection.Upsert(document))
|
||||
{
|
||||
TouchCache(document.ID, o);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// lock (this)
|
||||
// {
|
||||
// ODBDocument document = ODBMapper.MapValue(o) as ODBDocument;
|
||||
// if (DocumentCollection.Upsert(document))
|
||||
// {
|
||||
// TouchCache(document.ID, o);
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
public bool Delete(object o) => Delete(ODBMapper.MapValue(ODBMapper.GetDocumentID(o)));
|
||||
public bool Delete(ODBValue documentID)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (DocumentCollection.Delete(documentID))
|
||||
{
|
||||
if (objectCache.ContainsKey(documentID))
|
||||
objectCache.Remove(documentID);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// public bool Delete(object o) => Delete(ODBMapper.MapValue(ODBMapper.GetDocumentID(o)));
|
||||
// public bool Delete(ODBValue documentID)
|
||||
// {
|
||||
// lock (this)
|
||||
// {
|
||||
// if (DocumentCollection.Delete(documentID))
|
||||
// {
|
||||
// if (objectCache.ContainsKey(documentID))
|
||||
// objectCache.Remove(documentID);
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
public bool HasProperty(string propName)
|
||||
{
|
||||
propName = IndexPath.TranslatePropertyPath(ElementType, propName);
|
||||
// public bool HasProperty(string propName)
|
||||
// {
|
||||
// propName = IndexPath.TranslatePropertyPath(ElementType, propName);
|
||||
|
||||
ClassMapping classMapping = ODBMapper.GetMapping(ElementType) as ClassMapping;
|
||||
if (classMapping != null)
|
||||
{
|
||||
return classMapping.HasField(propName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// ClassMapping classMapping = ODBMapper.GetMapping(ElementType) as ClassMapping;
|
||||
// if (classMapping != null)
|
||||
// {
|
||||
// return classMapping.HasField(propName);
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
/* Indeces */
|
||||
public void EnsureIndex(string propertyPath, bool unique = false)
|
||||
{
|
||||
//string translatedPath = IndexPath.TranslatePropertyPath(ElementType, propertyPath);
|
||||
//DocumentCollection.EnsureIndex(translatedPath, translatedPath);
|
||||
EnsureIndeces(false, new string[] { propertyPath });
|
||||
}
|
||||
public void EnsureIndeces(params string[] propertyPaths) => EnsureIndeces(false, propertyPaths);
|
||||
public void EnsureIndeces(bool unique, params string[] propertyPaths)
|
||||
{
|
||||
for (int n = 0; n < propertyPaths.Length; n++)
|
||||
propertyPaths[n] = IndexPath.TranslatePropertyPath(ElementType, propertyPaths[n]);
|
||||
// /* Indeces */
|
||||
// public void EnsureIndex(string propertyPath, bool unique = false)
|
||||
// {
|
||||
// //string translatedPath = IndexPath.TranslatePropertyPath(ElementType, propertyPath);
|
||||
// //DocumentCollection.EnsureIndex(translatedPath, translatedPath);
|
||||
// EnsureIndeces(false, new string[] { propertyPath });
|
||||
// }
|
||||
// public void EnsureIndeces(params string[] propertyPaths) => EnsureIndeces(false, propertyPaths);
|
||||
// public void EnsureIndeces(bool unique, params string[] propertyPaths)
|
||||
// {
|
||||
// for (int n = 0; n < propertyPaths.Length; n++)
|
||||
// propertyPaths[n] = IndexPath.TranslatePropertyPath(ElementType, propertyPaths[n]);
|
||||
|
||||
DocumentCollection.EnsureIndeces(propertyPaths, false);
|
||||
}
|
||||
// DocumentCollection.EnsureIndeces(propertyPaths, false);
|
||||
// }
|
||||
|
||||
public void EnsureUniqueness(params string[] propertyPaths)
|
||||
{
|
||||
for (int n = 0; n < propertyPaths.Length; n++)
|
||||
propertyPaths[n] = IndexPath.TranslatePropertyPath(ElementType, propertyPaths[n]);
|
||||
// public void EnsureUniqueness(params string[] propertyPaths)
|
||||
// {
|
||||
// for (int n = 0; n < propertyPaths.Length; n++)
|
||||
// propertyPaths[n] = IndexPath.TranslatePropertyPath(ElementType, propertyPaths[n]);
|
||||
|
||||
DocumentCollection.EnsureUniqueness(propertyPaths);
|
||||
}
|
||||
// DocumentCollection.EnsureUniqueness(propertyPaths);
|
||||
// }
|
||||
|
||||
/* Object Cache */
|
||||
public bool UseStrongCache { get; private set; }
|
||||
Dictionary<ODBValue, object> objectCache = new Dictionary<ODBValue, object>();
|
||||
// /* Object Cache */
|
||||
// public bool UseStrongCache { get; private set; }
|
||||
// Dictionary<ODBValue, object> objectCache = new Dictionary<ODBValue, object>();
|
||||
|
||||
public void EnableStrongCache(bool enable)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (!enable)
|
||||
{
|
||||
foreach (ODBValue key in objectCache.Keys.ToArray())
|
||||
{
|
||||
if (!(objectCache[key] is WeakReference))
|
||||
objectCache.Remove(key);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (ODBValue key in objectCache.Keys.ToArray())
|
||||
{
|
||||
if ((objectCache[key] is WeakReference))
|
||||
objectCache[key] = (objectCache[key] as WeakReference).Target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// public void EnableStrongCache(bool enable)
|
||||
// {
|
||||
// lock (this)
|
||||
// {
|
||||
// if (!enable)
|
||||
// {
|
||||
// foreach (ODBValue key in objectCache.Keys.ToArray())
|
||||
// {
|
||||
// if (!(objectCache[key] is WeakReference))
|
||||
// objectCache.Remove(key);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// foreach (ODBValue key in objectCache.Keys.ToArray())
|
||||
// {
|
||||
// if ((objectCache[key] is WeakReference))
|
||||
// objectCache[key] = (objectCache[key] as WeakReference).Target;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private object GetCachedObject(ODBValue documentID)
|
||||
{
|
||||
if (objectCache.ContainsKey(documentID))
|
||||
{
|
||||
object o = objectCache[documentID];
|
||||
if (o is WeakReference)
|
||||
{
|
||||
WeakReference weak = o as WeakReference;
|
||||
if (weak.IsAlive)
|
||||
return weak.Target;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// private object GetCachedObject(ODBValue documentID)
|
||||
// {
|
||||
// if (objectCache.ContainsKey(documentID))
|
||||
// {
|
||||
// object o = objectCache[documentID];
|
||||
// if (o is WeakReference)
|
||||
// {
|
||||
// WeakReference weak = o as WeakReference;
|
||||
// if (weak.IsAlive)
|
||||
// return weak.Target;
|
||||
// else
|
||||
// return null;
|
||||
// }
|
||||
// return o;
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
private void TouchCache(ODBValue documentID, object o)
|
||||
{
|
||||
if (object.ReferenceEquals(o, null) && objectCache.ContainsKey(documentID))
|
||||
{
|
||||
objectCache.Remove(documentID);
|
||||
}
|
||||
else if (!object.ReferenceEquals(o, null))
|
||||
{
|
||||
if (UseStrongCache)
|
||||
objectCache[documentID] = o;
|
||||
else
|
||||
objectCache[documentID] = new WeakReference(o);
|
||||
}
|
||||
}
|
||||
// private void TouchCache(ODBValue documentID, object o)
|
||||
// {
|
||||
// if (object.ReferenceEquals(o, null) && objectCache.ContainsKey(documentID))
|
||||
// {
|
||||
// objectCache.Remove(documentID);
|
||||
// }
|
||||
// else if (!object.ReferenceEquals(o, null))
|
||||
// {
|
||||
// if (UseStrongCache)
|
||||
// objectCache[documentID] = o;
|
||||
// else
|
||||
// objectCache[documentID] = new WeakReference(o);
|
||||
// }
|
||||
// }
|
||||
|
||||
public object[] GetDocumentIDs()
|
||||
{
|
||||
return DocumentCollection.Index.Select((arg) => ODBMapper.UnmapValue(IDType, arg)).ToArray();
|
||||
}
|
||||
// public object[] GetDocumentIDs()
|
||||
// {
|
||||
// return DocumentCollection.Index.Select((arg) => ODBMapper.UnmapValue(IDType, arg)).ToArray();
|
||||
// }
|
||||
|
||||
public IEnumerable GetEnumeration()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
return new ObjectEnumeration(this, DocumentCollection.Index.ToArray());
|
||||
}
|
||||
}
|
||||
// public IEnumerable GetEnumeration()
|
||||
// {
|
||||
// lock (this)
|
||||
// {
|
||||
// return new ObjectEnumeration(this, DocumentCollection.Index.ToArray());
|
||||
// }
|
||||
// }
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
return GetEnumeration().GetEnumerator();
|
||||
}
|
||||
// public IEnumerator GetEnumerator()
|
||||
// {
|
||||
// return GetEnumeration().GetEnumerator();
|
||||
// }
|
||||
|
||||
public void Close()
|
||||
{
|
||||
DocumentCollection = null;
|
||||
}
|
||||
// public void Close()
|
||||
// {
|
||||
// DocumentCollection = null;
|
||||
// }
|
||||
|
||||
|
||||
class ObjectEnumeration : IEnumerable
|
||||
{
|
||||
ObjectCollection collection;
|
||||
IEnumerable<ODBValue> documentIDs;
|
||||
// class ObjectEnumeration : IEnumerable
|
||||
// {
|
||||
// ObjectCollection collection;
|
||||
// IEnumerable<ODBValue> documentIDs;
|
||||
|
||||
public ObjectEnumeration(ObjectCollection collection,IEnumerable<ODBValue> documentIDs)
|
||||
{
|
||||
this.collection = collection;
|
||||
this.documentIDs = documentIDs;
|
||||
}
|
||||
// public ObjectEnumeration(ObjectCollection collection,IEnumerable<ODBValue> documentIDs)
|
||||
// {
|
||||
// this.collection = collection;
|
||||
// this.documentIDs = documentIDs;
|
||||
// }
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
foreach (ODBValue documentID in this.documentIDs)
|
||||
{
|
||||
yield return this.collection.SelectByID(documentID);
|
||||
}
|
||||
}
|
||||
}
|
||||
// public IEnumerator GetEnumerator()
|
||||
// {
|
||||
// foreach (ODBValue documentID in this.documentIDs)
|
||||
// {
|
||||
// yield return this.collection.SelectByID(documentID);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
|
||||
public class ObjectCollection<T> : ObjectCollection where T:class
|
||||
{
|
||||
public ObjectCollection(ODBMapper odbmapper)
|
||||
:base(odbmapper,typeof(T))
|
||||
{}
|
||||
//public class ObjectCollection<T> : ObjectCollection where T:class
|
||||
//{
|
||||
// public ObjectCollection(ODBMapper odbmapper)
|
||||
// :base(odbmapper,typeof(T))
|
||||
// {}
|
||||
|
||||
public IEnumerable<T> SelectQuery(Query query) => base.Select(query).Cast<T>();
|
||||
public T Select(object id) => (T)base.SelectByID(id);
|
||||
// public IEnumerable<T> SelectQuery(Query query) => base.Select(query).Cast<T>();
|
||||
// public T Select(object id) => (T)base.SelectByID(id);
|
||||
|
||||
public bool Ensure(T o) => base.Ensure(o);
|
||||
public bool Insert(T o) => base.Insert(o);
|
||||
public bool Update(T o) => base.Update(o);
|
||||
public bool Upsert(T o) => base.Upsert(o);
|
||||
public void Delete(T o) => base.Delete(o);
|
||||
}
|
||||
// public bool Ensure(T o) => base.Ensure(o);
|
||||
// public bool Insert(T o) => base.Insert(o);
|
||||
// public bool Update(T o) => base.Update(o);
|
||||
// public bool Upsert(T o) => base.Upsert(o);
|
||||
// public void Delete(T o) => base.Delete(o);
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
using System;
|
||||
namespace ln.types.odb.ng
|
||||
{
|
||||
public class Reference<T> where T:class
|
||||
{
|
||||
ODBMapper mapper;
|
||||
ObjectCollection<T> Collection => mapper.GetCollection<T>();
|
||||
//public class Reference<T> where T:class
|
||||
//{
|
||||
// ODBMapper mapper;
|
||||
// ObjectCollection<T> Collection => mapper.GetCollection<T>();
|
||||
|
||||
internal object valueID;
|
||||
// internal object valueID;
|
||||
|
||||
public Reference(ODBMapper mapper)
|
||||
{
|
||||
this.mapper = mapper;
|
||||
}
|
||||
public Reference(ODBMapper mapper,T value)
|
||||
{
|
||||
this.mapper = mapper;
|
||||
this.Value = value;
|
||||
}
|
||||
// public Reference(ODBMapper mapper)
|
||||
// {
|
||||
// this.mapper = mapper;
|
||||
// }
|
||||
// public Reference(ODBMapper mapper,T value)
|
||||
// {
|
||||
// this.mapper = mapper;
|
||||
// this.Value = value;
|
||||
// }
|
||||
|
||||
public T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.valueID == null)
|
||||
return null;
|
||||
return this.Collection.Select(valueID);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Collection.Ensure(value);
|
||||
this.valueID = this.mapper.GetDocumentID(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// public T Value
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// if (this.valueID == null)
|
||||
// return null;
|
||||
// return this.Collection.Select(valueID);
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// this.Collection.Ensure(value);
|
||||
// this.valueID = this.mapper.GetDocumentID(value);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -16,8 +16,8 @@ namespace ln.types.odb.ng.mappings
|
|||
|
||||
public Type MappedType { get; }
|
||||
|
||||
public GetID getID { get; private set; } = (o) => Guid.NewGuid();
|
||||
public Type IDType { get; private set; }
|
||||
//public GetID getID { get; private set; } = (o) => Guid.NewGuid();
|
||||
//public Type IDType { get; private set; }
|
||||
|
||||
List<FieldInfo> mappedFields = new List<FieldInfo>();
|
||||
|
||||
|
@ -36,20 +36,20 @@ namespace ln.types.odb.ng.mappings
|
|||
if (fieldinfo.GetCustomAttribute<IgnoreFieldAttribute>() == null)
|
||||
{
|
||||
mappedFields.Add(fieldinfo);
|
||||
if (fieldinfo.GetCustomAttribute<DocumentIDAttribute>() != null)
|
||||
{
|
||||
getID = (o) => fieldinfo.GetValue(o);
|
||||
IDType = fieldinfo.FieldType;
|
||||
}
|
||||
//if (fieldinfo.GetCustomAttribute<DocumentIDAttribute>() != null)
|
||||
//{
|
||||
// getID = (o) => fieldinfo.GetValue(o);
|
||||
// IDType = fieldinfo.FieldType;
|
||||
//}
|
||||
}
|
||||
}
|
||||
foreach (PropertyInfo propInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
|
||||
{
|
||||
if (propInfo.GetCustomAttribute<DocumentIDAttribute>() != null)
|
||||
{
|
||||
getID = (o) => propInfo.GetValue(o);
|
||||
IDType = propInfo.PropertyType;
|
||||
}
|
||||
//if (propInfo.GetCustomAttribute<DocumentIDAttribute>() != null)
|
||||
//{
|
||||
// getID = (o) => propInfo.GetValue(o);
|
||||
// IDType = propInfo.PropertyType;
|
||||
//}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ODBDocument document = oval as ODBDocument;
|
||||
Document document = oval as Document;
|
||||
object o = Activator.CreateInstance(MappedType, true);
|
||||
|
||||
foreach (FieldInfo fieldInfo in mappedFields)
|
||||
|
@ -76,12 +76,13 @@ namespace ln.types.odb.ng.mappings
|
|||
ByReferenceAttribute byReferenceAttribute = fieldInfo.GetCustomAttribute<ByReferenceAttribute>();
|
||||
if (byReferenceAttribute != null)
|
||||
{
|
||||
Type ceType = byReferenceAttribute.ElementType ?? fieldInfo.FieldType;
|
||||
String cAlias = byReferenceAttribute.Alias ?? ceType.FullName;
|
||||
// ToDo: Implement Referentiel Mapping
|
||||
//Type ceType = byReferenceAttribute.ElementType ?? fieldInfo.FieldType;
|
||||
//String cAlias = byReferenceAttribute.Alias ?? ceType.FullName;
|
||||
|
||||
ObjectCollection objectCollection = mapper.GetCollection(ceType, cAlias);
|
||||
ODBValue refID = document[fieldInfo.Name];
|
||||
fieldInfo.SetValue(o, objectCollection.SelectByID(refID));
|
||||
//ObjectCollection objectCollection = mapper.GetStorage(ceType, cAlias);
|
||||
//ODBValue refID = document[fieldInfo.Name];
|
||||
//fieldInfo.SetValue(o, objectCollection.SelectByID(refID));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -104,53 +105,50 @@ namespace ln.types.odb.ng.mappings
|
|||
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))
|
||||
return ODBNull.Instance;
|
||||
|
||||
ODBDocument document = new ODBDocument();
|
||||
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;
|
||||
|
||||
return MapDocument(mapper, Guid.Empty, value);
|
||||
}
|
||||
|
||||
public Type GetFieldType(ODBMapper mapper,string fieldName)
|
||||
{
|
||||
foreach (FieldInfo fieldInfo in mappedFields)
|
||||
if (fieldInfo.Name.Equals(fieldName))
|
||||
if (fieldInfo.GetCustomAttribute<ByReferenceAttribute>() != null)
|
||||
{
|
||||
return mapper.GetDocumentIDType(fieldInfo.FieldType);
|
||||
} else
|
||||
{
|
||||
return fieldInfo.FieldType;
|
||||
}
|
||||
return fieldInfo.FieldType;
|
||||
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
|
@ -162,14 +160,14 @@ namespace ln.types.odb.ng.mappings
|
|||
|
||||
public ODBValue MapValue(ODBMapper mapper, object value)
|
||||
{
|
||||
return new ODBDocument();
|
||||
return new Document();
|
||||
}
|
||||
|
||||
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__"))
|
||||
return new object();
|
||||
|
||||
|
|
|
@ -20,13 +20,13 @@ namespace ln.types.odb.ng.mappings
|
|||
if (dType.GetInterfaces().Contains(typeof(IDictionary)))
|
||||
{
|
||||
IDictionary dictionary = value as IDictionary;
|
||||
ODBDocument document = new ODBDocument();
|
||||
Document document = new Document();
|
||||
|
||||
document["__asm__"] = value.GetType().Assembly.GetName().Name;
|
||||
document["__type__"] = value.GetType().FullName;
|
||||
|
||||
ODBDocument kTypes = new ODBDocument();
|
||||
ODBDocument vTypes = new ODBDocument();
|
||||
Document kTypes = new Document();
|
||||
Document vTypes = new Document();
|
||||
|
||||
document["__ktypes__"] = kTypes;
|
||||
document["__vtypes__"] = vTypes;
|
||||
|
@ -47,7 +47,7 @@ namespace ln.types.odb.ng.mappings
|
|||
|
||||
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);
|
||||
|
||||
if (dType.IsGenericType)
|
||||
|
@ -59,8 +59,8 @@ namespace ln.types.odb.ng.mappings
|
|||
Type kType = dType.GetGenericArguments()[0];
|
||||
Type vType = dType.GetGenericArguments()[1];
|
||||
|
||||
ODBDocument ktypes = document.Contains("__ktypes__") ? document["__ktypes__"].AsDocument : new ODBDocument();
|
||||
ODBDocument vtypes = document.Contains("__vtypes__") ? document["__vtypes__"].AsDocument : new ODBDocument();
|
||||
Document ktypes = document.Contains("__ktypes__") ? document["__ktypes__"] as Document : new Document();
|
||||
Document vtypes = document.Contains("__vtypes__") ? document["__vtypes__"] as Document : new Document();
|
||||
|
||||
foreach (ODBValue key in document.Keys)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -43,7 +43,14 @@ namespace ln.types.odb.values
|
|||
|
||||
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
|
||||
{
|
||||
object[] a = new object[items.Count];
|
||||
|
|
|
@ -94,7 +94,13 @@ namespace ln.types.odb.values
|
|||
|
||||
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();
|
||||
|
||||
|
@ -221,5 +227,21 @@ namespace ln.types.odb.values
|
|||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue