dev_timestamp
Harald Wolff 2019-03-26 12:54:02 +01:00
parent aa65fc9f4e
commit 035be47c45
31 changed files with 2395 additions and 589 deletions

43
CIDR.cs
View File

@ -13,6 +13,7 @@ using System.Linq;
using System.Collections.Generic;
using System.Collections;
using Newtonsoft.Json;
using LiteDB;
namespace ln.types
{
@ -35,7 +36,7 @@ namespace ln.types
return new CIDR(ip, w);
}
}
return new CIDR(ip,32);
return new CIDR(ip, 32);
}
private readonly uint _ip;
@ -45,7 +46,7 @@ namespace ln.types
public CIDR Network => new CIDR(_ip & _netmask, _netmask);
public CIDR Host => new CIDR(_ip, 0xffffffff);
public int Size => (1 << (32 - MaskWidth));
public int Size => (1 << (32 - MaskWidth));
public byte[] IPBytes
{
@ -115,12 +116,12 @@ namespace ln.types
for (w = 32; w > 0; w--)
{
if ((nm & (1 << (int)(32-w))) != 0)
if ((nm & (1 << (int)(32 - w))) != 0)
break;
}
for (uint n = w; n > 0; n--)
{
if ((nm & (1 << (int)(32-n))) == 0)
if ((nm & (1 << (int)(32 - n))) == 0)
throw new FormatException("Netmask with holes");
}
@ -136,7 +137,7 @@ namespace ln.types
uint newmask = maskFromWidth((uint)(MaskWidth + bits));
uint nip = _ip;
CIDR[] result = new CIDR[count];
for (int n=0;n<count;n++)
for (int n = 0; n < count; n++)
{
nip += (uint)(1 << (32 - MaskWidth - bits));
result[n] = new CIDR(nip, newmask);
@ -150,23 +151,32 @@ namespace ln.types
if (_netmask == 0xFFFFFFFF)
return String.Format("{0}", String.Join(".", IPBytes.Select((x) => x.ToString())));
else
return String.Format("{0}/{1}", String.Join(".", IPBytes.Select((x) => x.ToString())),getNetWidth(_netmask));
return String.Format("{0}/{1}", String.Join(".", IPBytes.Select((x) => x.ToString())), getNetWidth(_netmask));
}
public static implicit operator IPAddress(CIDR cidr)
{
return new IPAddress( cidr.IPBytes );
return new IPAddress(cidr.IPBytes);
}
public static implicit operator CIDR(IPAddress iPAddress)
{
return new CIDR(BitConverter.ToUInt32(iPAddress.GetAddressBytes().Reverse().ToArray(),0),0xFFFFFFFF);
return new CIDR(BitConverter.ToUInt32(iPAddress.GetAddressBytes().Reverse().ToArray(), 0), 0xFFFFFFFF);
}
public bool Contains(CIDR you)
{
return (you.MaskWidth >= MaskWidth) && ((you._ip & _netmask)==(_ip & _netmask));
return (you.MaskWidth >= MaskWidth) && ((you._ip & _netmask) == (_ip & _netmask));
}
public bool Contains(IEnumerable<CIDR> candidates)
{
foreach (CIDR ip in candidates)
if (Contains(ip))
return true;
return false;
}
public override int GetHashCode()
{
return (int)(_ip ^ _netmask);
@ -225,13 +235,17 @@ namespace ln.types
}
static bool ___init = ____init();
static bool ____init()
static CIDR()
{
BsonMapper.Global.RegisterType<CIDR>(
serialize: (ip) => ip.ToString(),
deserialize: (bson) => CIDR.Parse(bson.AsString)
);
List<JsonConverter> converters = new List<JsonConverter>();
converters.Add(new CIDRJsonConverter());
JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Converters = converters };
return true;
}
}
@ -243,15 +257,16 @@ namespace ln.types
return (objectType == typeof(CIDR));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
return CIDR.Parse(reader.ReadAsString());
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
writer.WriteValue((value as CIDR).ToString());
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.IO;
namespace ln.types
{
public static class Extensions
@ -14,5 +15,17 @@ namespace ln.types
return true;
}
public static int ReadInteger(this Stream stream)
{
byte[] b = new byte[4];
stream.Read(b, 0, 4);
return BitConverter.ToInt32(b,0);
}
public static void WriteInteger(this Stream stream,int i)
{
stream.Write(BitConverter.GetBytes(i), 0, 4);
}
}
}

34
GeoLocation.cs 100644
View File

@ -0,0 +1,34 @@
// /**
// * File: GeoLocation.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
{
public struct GeoLocation
{
public double Latitude;
public double Longitude;
public GeoLocation(double latitude,double longitude)
{
Latitude = latitude;
Longitude = longitude;
}
public override string ToString()
{
return String.Format("{0:F}{1}{2:F}{3}",
(Latitude < 0) ? -Latitude : Latitude,
(Latitude < 0) ? 'S':'N',
(Longitude < 0) ? -Longitude : Longitude,
(Longitude < 0) ? 'W' : 'E'
);
}
}
}

246
URI.cs 100644
View File

@ -0,0 +1,246 @@
// /**
// * File: URI.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.Text;
namespace ln.types
{
/**
* Quick and Dirty RFC3986 URI
*
**/
public class URI
{
public String Scheme { get; private set; } = String.Empty;
public String Authority { get; private set; } = String.Empty;
public String[] UserInfo { get; private set; } = new String[0];
public String Host { get; private set; } = String.Empty;
public String Port { get; private set; } = String.Empty;
public String Path { get; private set; } = String.Empty;
public String Query { get; private set; } = String.Empty;
public String Fragment { get; private set; } = String.Empty;
private URI()
{
}
public URI(String uri)
{
Parse(uri);
ParseAuthority();
}
public URI(String scheme, String authority, string path)
{
Parse(String.Format("{0}://{1}{2}", scheme, authority, path));
ParseAuthority();
}
public URI(String scheme,String authority,string path,string query,string fragment)
{
Scheme = scheme;
Authority = authority;
Path = path;
Query = query;
Fragment = fragment;
ParseAuthority();
}
public URI(URI uri, string path)
{
Parse(String.Format("{0}://{1}{2}", uri.Scheme, uri.Authority, path));
ParseAuthority();
}
public URI Follow(String path)
{
if (path.StartsWith("/",StringComparison.InvariantCulture))
{
return new URI(Scheme, Authority, path);
} else if (Path.EndsWith("/",StringComparison.InvariantCulture) || path.StartsWith("?",StringComparison.InvariantCulture) || path.StartsWith("#", StringComparison.InvariantCulture))
{
return new URI(Scheme, Authority, String.Format("{0}{1}", Path, path));
}
else
{
int indSlash = Path.LastIndexOf('/');
return new URI(Scheme, Authority, String.Format("{0}/{1}",Path.Substring(0,indSlash),path));
}
}
private void Parse(String uri)
{
char[] chUri = uri.ToCharArray();
int n = 0;
int m = 0;
// Scheme
while ((chUri[n] != ':') && ((++n) < chUri.Length)) { };
if (n < 2)
throw new FormatException(String.Format("URL malformed: {0}",uri));
Scheme = new string(chUri, 0, n);
n++;
if (n < chUri.Length)
{
if ((chUri.Length - n > 1) && (chUri[n] == '/') && (chUri[n+1] == '/'))
{
// Authority
n += 2;
m = n;
while (
(m < chUri.Length) &&
(chUri[m] != '/') &&
(chUri[m] != '?') &&
(chUri[m] != '#')
) { m++; }
Authority = new string(chUri, n, (m - n));
n = m;
}
// Path
m = n;
while (
(m < chUri.Length) &&
(chUri[m] != '?') &&
(chUri[m] != '#')
)
{ m++; }
Path = new string(chUri, n, (m - n));
n = m;
if (n < chUri.Length)
{
if (chUri[n] == '?')
{
n++;
m = n;
while (
(m < chUri.Length) &&
(chUri[m] != '#')
)
{ m++; }
Query = new string(chUri, n, (m - n));
n = m;
}
if ((n<chUri.Length) && (chUri[n] == '#'))
{
n++;
m = n;
while (
(m < chUri.Length) &&
(chUri[m] != '#')
)
{ m++; }
Fragment = new string(chUri, n, (m - n));
n = m;
}
if (n < chUri.Length)
throw new FormatException(String.Format("Malformed URI: {0}", uri));
}
}
}
private void ParseAuthority()
{
int indAt = Authority.IndexOf('@');
if (indAt != -1)
{
UserInfo = Authority.Substring(0, indAt).Split(':');
}
indAt++;
int indPort = Authority.IndexOf(':', indAt);
if (indPort != -1)
{
Host = Authority.Substring(indAt, indPort - indAt);
Port = Authority.Substring(indPort + 1);
}
else
{
Host = Authority.Substring(indAt);
}
}
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(Scheme);
stringBuilder.Append(':');
if (!String.Empty.Equals(Authority))
{
stringBuilder.Append("//");
if (UserInfo.Length > 0)
{
stringBuilder.Append(UserInfo[0]);
stringBuilder.Append('@');
}
stringBuilder.Append(Host);
if (!String.Empty.Equals(Port))
{
stringBuilder.Append(':');
stringBuilder.Append(Port);
}
}
stringBuilder.Append(Path);
if (!string.Empty.Equals(Query))
{
stringBuilder.Append("?");
stringBuilder.Append(Query);
}
if (!string.Empty.Equals(Fragment))
{
stringBuilder.Append('#');
stringBuilder.Append(Fragment);
}
return stringBuilder.ToString();
}
private int GetHashCode(String s)
{
return (s == null) ? -1 : s.GetHashCode();
}
public override int GetHashCode()
{
return GetHashCode(Scheme) ^ GetHashCode(Authority) ^ GetHashCode(Path) ^ GetHashCode(Query) ^ GetHashCode(Fragment);
}
public override bool Equals(object obj)
{
if (obj is URI)
{
URI other = obj as URI;
return Scheme.Equals(other.Scheme) && Authority.Equals(other.Authority) && Path.Equals(other.Path) && Query.Equals(other.Query) && Fragment.Equals(other.Fragment);
}
return false;
}
}
}

View File

@ -38,6 +38,9 @@
<HintPath>..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="LiteDB">
<HintPath>..\packages\LiteDB.4.1.4\lib\net40\LiteDB.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
@ -60,12 +63,30 @@
<Compile Include="odb\ODBFileStorage.cs" />
<Compile Include="odb\Storage.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="GeoLocation.cs" />
<Compile Include="URI.cs" />
<Compile Include="odb\ODBCollection.cs" />
<Compile Include="odb\ODBDocument.cs" />
<Compile Include="odb\values\ODBGuid.cs" />
<Compile Include="odb\values\ODBNull.cs" />
<Compile Include="odb\values\ODBStringValue.cs" />
<Compile Include="odb\values\ODBValue.cs" />
<Compile Include="odb\values\ODBInteger.cs" />
<Compile Include="odb\values\ODBLong.cs" />
<Compile Include="odb\values\ODBDouble.cs" />
<Compile Include="odb\ODBMapper.cs" />
<Compile Include="odb\ClassMapping.cs" />
<Compile Include="odb\values\ODBList.cs" />
<Compile Include="odb\ListMapping.cs" />
<Compile Include="odb\ODBCollection&lt;&gt;.cs" />
<Compile Include="odb\DictionaryMapping.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="sync\" />
<Folder Include="serialize\" />
<Folder Include="odb\" />
<Folder Include="threads\" />
<Folder Include="odb\values\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ln.logging\ln.logging.csproj">

109
odb/ClassMapping.cs 100644
View File

@ -0,0 +1,109 @@
using System;
using ln.types.odb.values;
using System.Reflection;
using System.Collections.Generic;
using ln.logging;
namespace ln.types.odb
{
public class DocumentIDAttribute : Attribute
{
}
public class ClassMapping : IODBMapping
{
public Type MappedType { get; }
public String IDField { get; private set; }
List<FieldInfo> mappedFields = new List<FieldInfo>();
public ClassMapping(Type type)
{
Logging.Log(LogLevel.DEBUG, "Constructing ClassMapping for {0}",type);
MappedType = type;
AddFields(type);
}
private void AddFields(Type type)
{
foreach (FieldInfo fieldinfo in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
if (fieldinfo.GetCustomAttribute<IgnoreFieldAttribute>() == null)
{
mappedFields.Add(fieldinfo);
if (fieldinfo.GetCustomAttribute<DocumentIDAttribute>() != null)
{
IDField = fieldinfo.Name;
}
}
}
if ((type != null) && !type.IsValueType && (!typeof(object).Equals(type.BaseType)))
{
AddFields(type.BaseType);
}
}
public object UnmapValue(ODBMapper mapper,ODBValue oval)
{
ODBDocument document = oval as ODBDocument;
object o = Activator.CreateInstance(MappedType, true);
foreach (FieldInfo fieldInfo in mappedFields)
{
object fv = ODBMapper.Default.UnmapValue(fieldInfo.FieldType,document[fieldInfo.Name]);
fieldInfo.SetValue(o, fv);
}
return o;
}
public ODBValue MapValue(ODBMapper mapper,object value)
{
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 = ODBMapper.Default.MapValue(fv);
document[fieldInfo.Name] = ov;
}
if (IDField != null)
{
document.ID = document[IDField];
}
return document;
}
}
public class ObjectMapping : IODBMapping
{
public ODBValue MapValue(ODBMapper mapper, object value)
{
return new ODBDocument();
}
public object UnmapValue(ODBMapper mapper, ODBValue oval)
{
if (oval is ODBDocument)
{
ODBDocument document = oval.AsDocument;
if (!document.Contains("__type__"))
return new object();
Type dType = Assembly.Load(document["__asm__"].AsString).GetType(document["__type__"].AsString);
return mapper.UnmapValue(dType, oval);
}
else
{
return oval.Value;
}
}
}
}

View File

@ -0,0 +1,66 @@
using System;
using ln.types.odb.values;
using System.Linq;
using System.Collections;
using System.Reflection;
using Castle.Components.DictionaryAdapter;
using System.Collections.Generic;
namespace ln.types.odb
{
public class DictionaryMapping : IODBMapping
{
public DictionaryMapping()
{
}
public ODBValue MapValue(ODBMapper mapper, object value)
{
Type dType = value.GetType();
if (dType.GetInterfaces().Contains(typeof(IDictionary)))
{
IDictionary dictionary = value as IDictionary;
ODBDocument document = new ODBDocument();
document["__asm__"] = value.GetType().Assembly.GetName().Name;
document["__type__"] = value.GetType().FullName;
foreach (object key in dictionary.Keys)
{
object v = dictionary[key];
document[mapper.MapValue(key)] = mapper.MapValue(v);
}
return document;
}
throw new NotImplementedException();
}
public object UnmapValue(ODBMapper mapper, ODBValue oval)
{
ODBDocument document = oval.AsDocument;
Type dType = Assembly.Load(document["__asm__"].AsString).GetType(document["__type__"].AsString);
if (dType.IsGenericType)
{
IDictionary dictionary = (IDictionary)Activator.CreateInstance(dType, true);
if (dType.GetGenericTypeDefinition().Equals(typeof(Dictionary<,>)))
{
Type kType = dType.GetGenericArguments()[0];
Type vType = dType.GetGenericArguments()[1];
foreach (ODBValue key in document.Keys)
{
if (!key.Equals("__asm__") && !key.Equals("__type__"))
dictionary.Add(mapper.UnmapValue(kType, key), mapper.UnmapValue(vType, document[key]));
}
return dictionary;
}
}
throw new NotSupportedException();
}
}
}

59
odb/ListMapping.cs 100644
View File

@ -0,0 +1,59 @@
// /**
// * File: ListMapping.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.values;
using System.Collections;
using System.Linq;
namespace ln.types.odb
{
public class ListMapping : IODBMapping
{
public Type TargetType { get; }
public ListMapping(Type targetType)
{
TargetType = targetType;
}
public object UnmapValue(ODBMapper mapper,ODBValue oval)
{
ODBList list = oval as ODBList;
if (TargetType.IsArray)
{
Array a = Array.CreateInstance(TargetType.GetElementType(), list.Count);
for (int n = 0; n < list.Count; n++)
a.SetValue(list[n], n);
return a;
} else if (TargetType.GetInterfaces().Contains(typeof(IList)))
{
IList ilist = (IList)Activator.CreateInstance(TargetType, true);
for (int n = 0; n < list.Count; n++)
ilist.Add(list[n]);
return ilist;
}
throw new NotImplementedException();
}
public ODBValue MapValue(ODBMapper mapper,object value)
{
ODBList list = new ODBList();
foreach (object item in (IEnumerable)value)
{
list.Add(ODBMapper.Default.MapValue(item));
}
return list;
}
}
}

View File

@ -14,165 +14,70 @@ using Castle.DynamicProxy;
using ln.types.serialize;
using Castle.Components.DictionaryAdapter;
using System.Linq;
using ln.logging;
using ln.types.odb.values;
namespace ln.types.odb
{
public class ODB<T> : ODB where T: IPersistent
{
public T Root
{
get => (T)RootObject;
}
public ODB(String basePath)
:base(basePath, typeof(T))
{
}
}
public class ODB
public class ODB : IDisposable
{
public String BasePath { get; set; }
public IPersistent RootObject { get; protected set; }
private Type RootType;
private Storage Storage { get; set; }
private Dictionary<Guid, PreparedObject> objectCache = new Dictionary<Guid, PreparedObject>();
Dictionary<string, ODBCollection> collections = new Dictionary<string, ODBCollection>();
public ODB(string basePath)
{
BasePath = Path.GetFullPath(basePath);
Storage = new ODBFileStorage(basePath);
if (!Directory.Exists(BasePath))
Directory.CreateDirectory(BasePath);
}
public ODB(String basePath, Type rootType)
: this(basePath)
public ODBCollection GetCollection(string colName)
{
RootType = rootType;
Initialize();
if (!collections.ContainsKey(colName))
collections[colName] = new ODBCollection(this, colName);
return collections[colName];
}
public ODB(String basePath,IPersistent rootObject)
: this(basePath)
public ODBCollection<T> GetCollection<T>() where T:class
{
RootType = rootObject.GetType();
RootObject = rootObject;
Initialize();
return new ODBCollection<T>(this);
}
internal void DisposeCollection(ODBCollection collection)
{
ODBCollection check = collections[collection.CollectionName];
if (check == collection)
collections.Remove(collection.CollectionName);
}
private void Initialize()
{
if (RootObject == null)
{
string rootHint = Path.Combine(BasePath, "root.hint");
if (File.Exists(rootHint))
{
string rootID = File.ReadAllText(rootHint);
Guid persistenceID = Guid.Parse(rootID);
RootObject = LoadPersistent(persistenceID);
}
else
{
RootObject = (IPersistent)Activator.CreateInstance(RootType);
string rootID = RootObject.GetPersistenceID().ToString();
SavePersistent(RootObject);
File.WriteAllText(rootHint, rootID);
}
}
}
public bool Contains(Guid persistenceID)
public void Dispose()
{
return Storage.Contains(persistenceID) || objectCache.ContainsKey(persistenceID);
foreach (ODBCollection col in collections.Values.ToArray())
{
col.Dispose();
}
}
public void SavePersistent(IPersistent o) => SavePersistent(o, true);
public void SavePersistent(IPersistent o,bool recurse)
static ODB()
{
lock (this)
{
SaveCollector saveCollector = new SaveCollector(this);
saveCollector.Add(o);
foreach (PreparedObject preparedObject in saveCollector.PreparedToSave)
{
Storage.Store(preparedObject);
objectCache[preparedObject.PersistenceID] = preparedObject;
}
}
new ODBDocument();
new ODBNull();
new ODBStringValue();
new ODBList();
new ODBInteger();
new ODBUInteger();
new ODBLong();
new ODBULong();
new ODBDouble();
new ODBGuid();
}
public T LoadPersistent<T>(Guid persistenceID) => (T)LoadPersistent(persistenceID);
public IPersistent LoadPersistent(Guid persistenceID)
{
if (!Contains(persistenceID))
throw new KeyNotFoundException();
PreparedObject preparedObject = GetCachedPersistent(persistenceID);
if (preparedObject == null)
{
preparedObject = new PreparedObject(this, typeof(IPersistent), persistenceID);
if (!Storage.Load(preparedObject))
throw new IOException(String.Format("unable to load IPersistent({0})",persistenceID));
preparedObject.CreateInstance();
objectCache.Add(persistenceID,preparedObject);
}
return preparedObject.Instance;
}
private PreparedObject GetCachedPersistent(Guid persistenceID)
{
lock (this)
{
if (objectCache.ContainsKey(persistenceID))
{
return objectCache[persistenceID];
}
}
return null;
}
class SaveCollector
{
public ODB ODB { get; }
public IEnumerable<PreparedObject> PreparedToSave => preparedObjects.Values;
private Dictionary<Guid, PreparedObject> preparedObjects = new Dictionary<Guid, PreparedObject>();
public SaveCollector(ODB odb)
{
ODB = odb;
}
public void Add(IPersistent persistent)
{
PreparedObject preparedObject = new PreparedObject(ODB,persistent);
PreparedObject cachedObject = ODB.GetCachedPersistent(preparedObject.PersistenceID);
if (!preparedObject.InstanceEquals(cachedObject) && !preparedObjects.ContainsKey(preparedObject.PersistenceID))
{
preparedObjects.Add(preparedObject.PersistenceID, preparedObject);
foreach (IPersistent referencedPersistent in preparedObject.ReferencedPersistents)
{
Add(referencedPersistent);
}
}
}
}
}
}
}

View File

@ -0,0 +1,419 @@
using System;
using System.Collections;
using System.Collections.Generic;
using ln.types.odb.values;
using System.IO;
using System.Net.Mime;
using System.Security.AccessControl;
using System.Linq;
using System.ComponentModel.Design.Serialization;
using System.ComponentModel;
using ln.logging;
namespace ln.types.odb
{
public class ODBCollection : IEnumerable<ODBDocument>, IDisposable
{
public ODB ODB { get; }
public String CollectionName { get; }
public DocumentIndex Index => documentIndex;
FileStream fileStream;
DocumentIndex documentIndex;
internal ODBCollection(ODB odb,string collectionName)
{
ODB = odb;
CollectionName = collectionName;
Initialize();
}
private void Initialize()
{
fileStream = new FileStream(Path.Combine(ODB.BasePath, String.Format("{0}.col",CollectionName)),FileMode.OpenOrCreate,FileAccess.ReadWrite);
documentIndex = new DocumentIndex(fileStream);
}
public void Close()
{
Dispose();
}
public bool Insert(ODBDocument document)
{
DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(document.ID);
if (die == null)
{
byte[] docBytes = document.ToStorage();
die = documentIndex.FindUnused(docBytes.Length);
die.Update(document.ID,docBytes);
return true;
}
return false;
}
public bool Update(ODBDocument document)
{
DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(document.ID);
if (die != null)
{
byte[] docBytes = document.ToStorage();
if (die.BufferLength < docBytes.Length)
{
DocumentIndex.DocumentIndexEntry ndie = documentIndex.FindUnused(docBytes.Length);
die.DocumentID = ODBNull.Instance;
ndie.Update(document.ID, docBytes);
die.Release();
}
else
{
die.Update(document.ID, docBytes);
}
return true;
}
return false;
}
public bool Upsert(ODBDocument document)
{
byte[] docBytes = document.ToStorage();
DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(document.ID);
DocumentIndex.DocumentIndexEntry rdie = null;
if ((die == null) || (die.BufferLength < docBytes.Length))
{
rdie = die;
die = documentIndex.FindUnused(docBytes.Length);
}
if (rdie != null)
rdie.DocumentID = ODBNull.Instance;
die.Update(document.ID, docBytes);
if (rdie != null)
rdie.Release();
return true;
}
public ODBDocument GetDocumentByID(ODBValue id)
{
Logging.Log(LogLevel.DEBUG, "ODBCollection.GetDocumentByID(): {0}",id);
DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(id);
if (die != null)
{
byte[] storageBytes = die.ReadStorageBytes();
ODBDocument document = new ODBDocument(storageBytes, 0, storageBytes.Length);
return document;
}
return null;
}
public IEnumerable<ODBDocument> Find(string propertyName, ODBValue value)
{
foreach (ODBDocument document in this)
{
if (value.Equals(document[propertyName]))
yield return document;
}
}
public ODBDocument FindOne(string propertyName, ODBValue value)
{
foreach (ODBDocument document in this)
{
if (value.Equals(document[propertyName]))
return document;
}
return null;
}
public IEnumerator<ODBDocument> GetEnumerator()
{
foreach (ODBValue id in documentIndex.ToArray())
{
yield return GetDocumentByID(id);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Dispose()
{
ODB.DisposeCollection(this);
if (fileStream != null)
{
fileStream.Dispose();
fileStream = null;
}
documentIndex = null;
}
public class DocumentIndex : IEnumerable<ODBValue>
{
public Stream StorageStream { get; }
public DocumentIndexEntry Head { get; private set; }
private Dictionary<ODBValue, DocumentIndexEntry> idLookup = new Dictionary<ODBValue, DocumentIndexEntry>();
public DocumentIndex(Stream stream)
{
StorageStream = stream;
Head = new DocumentIndexEntry(this);
}
public IEnumerable<DocumentIndexEntry> IndexEntries
{
get
{
DocumentIndexEntry entry = Head;
while (entry != null)
{
yield return entry;
entry = entry.Next;
}
}
}
public DocumentIndexEntry Lookup(ODBValue ID)
{
foreach (DocumentIndexEntry die in IndexEntries)
{
if (ID.Equals(die.DocumentID))
return die;
}
return null;
}
public DocumentIndexEntry FindUnused(int minLength)
{
foreach (DocumentIndexEntry die in IndexEntries)
{
if (die.IsUnused && (die.BufferLength > minLength))
return die;
if (die.Next == null)
return die.Extend(minLength);
}
return null;
}
public class DocumentIndexEntry
{
public DocumentIndex Index { get; }
public DocumentIndexEntry Next { get; private set; }
public DocumentIndexEntry Last { get; private set; }
public long Offset { get; private set; }
public int BufferLength { get; private set; }
public long NextOffset => Offset + BufferLength + 4;
private ODBValue documentID;
public ODBValue DocumentID
{
get => documentID;
set
{
lock (Index)
{
if (!ODBNull.Instance.Equals(documentID))
{
Index.idLookup.Remove(documentID);
}
documentID = value;
if (!ODBNull.Instance.Equals(documentID))
{
Index.idLookup.Add(documentID, this);
}
}
}
}
public bool IsUnused => (ODBNull.Instance.Equals(documentID));
public DocumentIndexEntry(DocumentIndex index)
: this(index, 0)
{ }
private DocumentIndexEntry(DocumentIndex index, long offset)
{
Index = index;
Offset = offset;
Read();
}
private DocumentIndexEntry(DocumentIndexEntry lastEntry,int bufferLength)
{
Last = lastEntry;
Last.Next = this;
Index = lastEntry.Index;
Offset = lastEntry.NextOffset;
BufferLength = bufferLength;
WriteHeader();
Release();
}
private DocumentIndexEntry(DocumentIndexEntry lastEntry)
{
Last = lastEntry;
Index = lastEntry.Index;
Offset = lastEntry.NextOffset;
if (Last.Next != null)
{
Next = Last.Next;
Last.Next = this;
Next.Last = this;
BufferLength = (int)(Next.Offset - Offset - 4);
WriteHeader();
Release();
}
else
{
Last.Next = this;
Read();
}
}
private void Read()
{
lock (Index)
{
if (Offset >= Index.StorageStream.Length)
{
BufferLength = 0;
DocumentID = ODBNull.Instance;
}
else
{
Index.StorageStream.Position = Offset;
BufferLength = Index.StorageStream.ReadInteger();
Index.StorageStream.Position = Offset + 4;
DocumentID = ODBValue.Read(Index.StorageStream);
if (NextOffset < Index.StorageStream.Length)
{
Next = new DocumentIndexEntry(this);
}
}
}
}
public void Update(ODBValue id,byte[] storageBytes)
{
lock (Index)
{
if (BufferLength < storageBytes.Length)
throw new ArgumentOutOfRangeException();
if (BufferLength > (storageBytes.Length + 32))
{
Split(storageBytes.Length);
}
Index.StorageStream.Position = Offset + 4;
Index.StorageStream.Write(storageBytes, 0, storageBytes.Length);
DocumentID = id;
}
}
public void Release()
{
lock (Index)
{
DocumentID = ODBNull.Instance;
Index.StorageStream.Position = Offset + 4;
Index.StorageStream.Write(new byte[BufferLength], 0, BufferLength);
if ((Next != null) && Next.IsUnused)
{
Combine();
}
if ((Last != null) && Last.IsUnused)
{
Last.Combine();
}
}
}
public DocumentIndexEntry Extend(int length)
{
if (Next == null)
{
if ((Last == null) && (IsUnused))
{
BufferLength = length;
WriteHeader();
Release();
return this;
}
return new DocumentIndexEntry(this, length);
}
throw new NotSupportedException();
}
private void Split(int length)
{
BufferLength = length;
DocumentIndexEntry dieInsert = new DocumentIndexEntry(this);
WriteHeader();
}
private void Combine()
{
BufferLength += Next.BufferLength + 4;
Next = Next.Next;
if (Next != null)
Next.Last = this;
WriteHeader();
}
private void WriteHeader()
{
lock (Index)
{
Index.StorageStream.Position = Offset;
Index.StorageStream.WriteInteger(BufferLength);
}
}
public byte[] ReadStorageBytes()
{
byte[] buffer = new byte[BufferLength];
lock (Index)
{
Index.StorageStream.Position = Offset + 4;
Index.StorageStream.Read(buffer, 0, BufferLength);
}
return buffer;
}
}
public IEnumerator<ODBValue> GetEnumerator()
{
return idLookup.Keys.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
}

View File

@ -0,0 +1,109 @@
using System;
using System.Collections;
using System.Collections.Generic;
using ln.types.odb.values;
namespace ln.types.odb
{
public class ODBCollection<T> : IEnumerable<T> where T:class
{
public ODB ODB { get; }
public Type ElementType { get; }
ODBCollection collection;
Dictionary<ODBValue, WeakReference<T>> objectCache = new Dictionary<ODBValue, WeakReference<T>>();
internal ODBCollection(ODB odb)
{
ODB = odb;
ElementType = typeof(T);
collection = new ODBCollection(odb, ElementType.FullName);
}
public T this[ODBValue documentID]
{
get => Select(documentID);
}
public T GetCachedObject(ODBValue documentID)
{
if (objectCache.ContainsKey(documentID))
{
T o = null;
if (objectCache[documentID].TryGetTarget(out o))
return o;
}
return null;
}
public void TouchCache(ODBValue documentID,T o)
{
if ((o == null)&&objectCache.ContainsKey(documentID))
{
objectCache.Remove(documentID);
}
else if (o != null)
{
objectCache[documentID] = new WeakReference<T>(o);
}
}
public T SelectOne(string fieldName, object value)
{
ODBDocument document = collection.FindOne(fieldName, ODBMapper.Default.MapValue(value));
if (document != null)
{
return Select(document.ID);
}
return null;
}
public IEnumerable<T> Select(string fieldName, object value)
{
foreach (ODBDocument document in collection.Find(fieldName, ODBMapper.Default.MapValue(value)))
{
yield return Select(document.ID);
}
}
public T Select(ODBValue documentID)
{
T o = GetCachedObject(documentID);
if (o == null)
{
ODBDocument document = collection.GetDocumentByID(documentID);
o = ODBMapper.Default.ToNativeValue<T>(document);
TouchCache(documentID, o);
}
return o;
}
public bool Insert(T o)
{
ODBDocument document = ODBMapper.Default.MapValue(o) as ODBDocument;
return collection.Insert(document);
}
public bool Update(T o)
{
ODBDocument document = ODBMapper.Default.MapValue(o) as ODBDocument;
return collection.Update(document);
}
public bool Upsert(T o)
{
ODBDocument document = ODBMapper.Default.MapValue(o) as ODBDocument;
return collection.Upsert(document);
}
public IEnumerator<T> GetEnumerator()
{
foreach (ODBValue documentID in collection.Index)
{
yield return Select(documentID);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

109
odb/ODBDocument.cs 100644
View File

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.IO;
using ln.types.odb.values;
using System.Linq;
namespace ln.types.odb
{
public class ODBDocument : ODBValue
{
private Dictionary<ODBValue, ODBValue> properties = new Dictionary<ODBValue, ODBValue>();
public ODBDocument()
:base(0x1000)
{
}
public ODBValue ID { get; set; } = new ODBGuid();
public ODBDocument(byte[] bytes,int offset,int length)
:this()
{
int endOffset = offset + length;
ID = ODBValue.Deserialize(bytes, ref offset);
int nProps = BitConverter.ToInt32(bytes, offset);
offset += 4;
for (int n=0;n<nProps;n++)
{
ODBStringValue propName = ODBValue.Deserialize(bytes,ref offset) as ODBStringValue;
ODBValue propValue = ODBValue.Deserialize(bytes, ref offset);
properties.Add(propName, propValue);
}
if (offset > endOffset)
throw new FormatException("ODBDocument deserialization read behind end of buffer");
}
public ODBValue this[ODBValue propName]
{
get
{
if (properties.ContainsKey(propName))
return properties[propName];
return ODBNull.Instance;
}
set
{
if (ODBNull.Instance.Equals(value) && properties.ContainsKey(propName))
{
properties.Remove(propName);
}
else
{
properties[propName] = value;
}
}
}
public IEnumerable<ODBValue> Keys => properties.Keys;
public bool Contains(ODBStringValue propName)
{
return !ODBNull.Instance.Equals(this[propName]);
}
public override byte[] ToStorage()
{
MemoryStream stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(stream);
ID.Store(writer);
writer.Write(properties.Count);
foreach (ODBStringValue propName in properties.Keys)
{
ODBValue propValue = properties[propName];
propName.Store(writer);
propValue.Store(writer);
}
return stream.ToArray();
}
public override string ToString()
{
return String.Format("[ODBDocument ID={0} {1}]", ID.ToString(),String.Join(" ",properties.Select(kv=> String.Format("{0}={1}",kv.Key,kv.Value))));
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj is ODBDocument)
{
ODBDocument you = obj as ODBDocument;
return ID.Equals(you.ID);
}
return false;
}
static ODBDocument()
{
RegisterDeserializer(0x1000, (b,o,l) => new ODBDocument(b,o,l));
}
}
}

View File

@ -17,135 +17,143 @@ using System.Linq;
using System.Reflection;
namespace ln.types.odb
{
public class ODBFileStorage : Storage
{
public String BasePath { get; set; }
public int StorageVersion { get; } = 0x01;
//public class ODBFileStorage : Storage
//{
// public String BasePath { get; set; }
// public int StorageVersion { get; } = 0x01;
public ODBFileStorage(string basePath)
{
BasePath = Path.GetFullPath(basePath);
if (!Directory.Exists(BasePath))
{
Directory.CreateDirectory(BasePath);
}
}
// public ODBFileStorage(string basePath)
// {
// BasePath = Path.GetFullPath(basePath);
// if (!Directory.Exists(BasePath))
// {
// Directory.CreateDirectory(BasePath);
// }
// }
private string GetPersistentPath(Guid persistenceID)
{
byte[] idBytes = persistenceID.ToByteArray();
return Path.Combine(BasePath, BitConverter.ToString(idBytes, 0, 4));
}
// private string GetPersistentPath(Guid persistenceID)
// {
// byte[] idBytes = persistenceID.ToByteArray();
// return Path.Combine(BasePath, BitConverter.ToString(idBytes, 0, 4));
// }
public override bool Contains(Guid persistenceID)
{
string fn = Path.Combine(GetPersistentPath(persistenceID), String.Format("{0}.0", persistenceID));
return File.Exists(fn);
}
// public override bool Contains(Guid persistenceID)
// {
// string fn = Path.Combine(GetPersistentPath(persistenceID), String.Format("{0}.0", persistenceID));
// return File.Exists(fn);
// }
public override bool Store(PreparedObject preparedObject)
{
string targetPath = GetPersistentPath(preparedObject.PersistenceID);
String fnbase = Path.Combine(targetPath, preparedObject.PersistenceID.ToString());
// public override bool Store(PreparedObject preparedObject)
// {
// string targetPath = GetPersistentPath(preparedObject.PersistenceID);
// String fnbase = Path.Combine(targetPath, preparedObject.PersistenceID.ToString());
if (!Directory.Exists(targetPath))
Directory.CreateDirectory(targetPath);
// if (!Directory.Exists(targetPath))
// Directory.CreateDirectory(targetPath);
String fnn = String.Format("{0}.new", fnbase);
// String fnn = String.Format("{0}.new", fnbase);
using (FileStream fs = new FileStream(fnn, FileMode.CreateNew))
{
ToStream(preparedObject, fs);
fs.Close();
}
// if (File.Exists(fnn))
// File.Delete(fnn);
for (int n = 5; n > 0; n--)
{
string fn1 = String.Format("{0}.{1}", fnbase, n - 1);
string fn2 = String.Format("{0}.{1}", fnbase, n);
// using (FileStream fs = new FileStream(fnn, FileMode.CreateNew))
// {
// ToStream(preparedObject, fs);
// fs.Close();
// }
if (File.Exists(fn1))
File.Move(fn1, fn2);
}
// for (int n = 5; n > 0; n--)
// {
// string fn1 = String.Format("{0}.{1}", fnbase, n - 1);
// string fn2 = String.Format("{0}.{1}", fnbase, n);
string fn = String.Format("{0}.{1}", fnbase, 0);
File.Move(fnn, fn);
// if (File.Exists(fn1))
// {
// if (File.Exists(fn2))
// File.Delete(fn2);
return true;
}
// File.Move(fn1, fn2);
// }
// }
// string fn = String.Format("{0}.{1}", fnbase, 0);
// File.Move(fnn, fn);
// return true;
// }
public override bool Load(PreparedObject preparedObject)
{
string targetPath = GetPersistentPath(preparedObject.PersistenceID);
String fnbase = Path.Combine(targetPath, preparedObject.PersistenceID.ToString());
string fn = String.Format("{0}.0", fnbase);
// public override bool Load(PreparedObject preparedObject)
// {
// string targetPath = GetPersistentPath(preparedObject.PersistenceID);
// String fnbase = Path.Combine(targetPath, preparedObject.PersistenceID.ToString());
// string fn = String.Format("{0}.0", fnbase);
using (FileStream fs = new FileStream(fn, FileMode.Open))
{
FromStream(fs, preparedObject);
fs.Close();
}
return true;
}
// using (FileStream fs = new FileStream(fn, FileMode.Open))
// {
// FromStream(fs, preparedObject);
// fs.Close();
// }
// return true;
// }
private void ToStream(PreparedObject preparedObject,Stream stream)
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(StorageVersion);
writer.Write(DateTimeOffset.Now.ToUnixTimeMilliseconds());
writer.Write(preparedObject.PreparedType.Assembly.FullName);
writer.Write(preparedObject.PreparedType.FullName);
// private void ToStream(PreparedObject preparedObject,Stream stream)
// {
// using (BinaryWriter writer = new BinaryWriter(stream))
// {
// writer.Write(StorageVersion);
// writer.Write(DateTimeOffset.Now.ToUnixTimeMilliseconds());
// writer.Write(preparedObject.PreparedType.Assembly.GetName().Name);
// writer.Write(preparedObject.PreparedType.FullName);
string[] fieldNames = preparedObject.StoredFieldNames;
// string[] fieldNames = preparedObject.StoredFieldNames;
writer.Write(fieldNames.Length);
foreach (String fieldName in fieldNames)
{
byte[] fieldBytes = preparedObject.GetFieldBytes(fieldName);
writer.Write(fieldName);
writer.Write(fieldBytes.Length);
writer.Write(fieldBytes);
}
// writer.Write(fieldNames.Length);
// foreach (String fieldName in fieldNames)
// {
// byte[] fieldBytes = preparedObject.GetFieldBytes(fieldName);
// writer.Write(fieldName);
// writer.Write(fieldBytes.Length);
// writer.Write(fieldBytes);
// }
writer.Close();
}
}
// writer.Close();
// }
// }
private void FromStream(Stream stream,PreparedObject preparedObject)
{
using (BinaryReader reader = new BinaryReader(stream))
{
if (reader.ReadInt32() != StorageVersion)
throw new FormatException("Unsupported Storage Version");
// private void FromStream(Stream stream,PreparedObject preparedObject)
// {
// using (BinaryReader reader = new BinaryReader(stream))
// {
// if (reader.ReadInt32() != StorageVersion)
// throw new FormatException("Unsupported Storage Version");
DateTime timestamp = DateTimeOffset.FromUnixTimeMilliseconds(reader.ReadInt64()).DateTime;
// DateTime timestamp = DateTimeOffset.FromUnixTimeMilliseconds(reader.ReadInt64()).DateTime;
string assemblyName = reader.ReadString();
string typeName = reader.ReadString();
// string assemblyName = reader.ReadString();
// string typeName = reader.ReadString();
Assembly assembly = Assembly.Load(assemblyName);
Type targetType = assembly.GetType(typeName);
// Assembly assembly = Assembly.Load(assemblyName);
// Type targetType = assembly.GetType(typeName);
preparedObject.ReConfigure(targetType,timestamp);
// preparedObject.ReConfigure(targetType,timestamp);
int nStoredFields = reader.ReadInt32();
// int nStoredFields = reader.ReadInt32();
for (int n = 0; n < nStoredFields; n++)
{
string fieldName = reader.ReadString();
int nBytes = reader.ReadInt32();
byte[] fieldBytes = reader.ReadBytes(nBytes);
preparedObject.SetFieldBytes(fieldName, fieldBytes);
}
// for (int n = 0; n < nStoredFields; n++)
// {
// string fieldName = reader.ReadString();
// int nBytes = reader.ReadInt32();
// byte[] fieldBytes = reader.ReadBytes(nBytes);
// preparedObject.SetFieldBytes(fieldName, fieldBytes);
// }
reader.Close();
}
}
// reader.Close();
// }
// }
}
//}
}

220
odb/ODBMapper.cs 100644
View File

@ -0,0 +1,220 @@
using System;
using ln.types.odb.values;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;
using System.Reflection;
using System.Linq;
using System.Collections;
namespace ln.types.odb
{
public class IgnoreFieldAttribute : Attribute
{
}
public delegate ODBValue ODBMap(ODBMapper mapper, object value);
public delegate object ODBUnmap(ODBMapper mapper, ODBValue oval);
public delegate ODBValue ODBMap<T>(ODBMapper mapper, T value);
public delegate T ODBUnmap<T>(ODBMapper mapper, ODBValue oval);
public interface IODBMapping
{
ODBValue MapValue(ODBMapper mapper, object value);
object UnmapValue(ODBMapper mapper, ODBValue oval);
}
public interface IODBMapping<T>
{
ODBValue MapValue(ODBMapper mapper, T value);
T UnmapValue(ODBMapper mapper, ODBValue oval);
}
public class SimpleMapping : IODBMapping
{
ODBMap map;
ODBUnmap unmap;
public SimpleMapping(ODBMap map,ODBUnmap unmap)
{
this.map = map;
this.unmap = unmap;
}
public ODBValue MapValue(ODBMapper mapper, object value)
{
return map(mapper, value);
}
public object UnmapValue(ODBMapper mapper, ODBValue oval)
{
return unmap(mapper, oval);
}
}
public class SimpleMapping<T> : SimpleMapping
{
public SimpleMapping(ODBMap<T> map, ODBUnmap<T> unmap)
:base((mapper, value) => map(mapper,(T)value),(mapper, oval) => unmap(mapper,oval))
{}
}
public class ODBMapper
{
public static ODBMapper Default { get; } = new ODBMapper();
Dictionary<Type, IODBMapping> mappings = new Dictionary<Type, IODBMapping>();
private ODBMapper()
{
RegisterMapping<string>(
(mapper, value) => new ODBStringValue(value),
(mapper, oval) => oval.AsString
);
RegisterMapping<int>(
(mapper, value) => new ODBInteger(value),
(mapper, oval) => oval.AsInt
);
RegisterMapping<short>(
(mapper, value) => new ODBInteger(value),
(mapper, oval) => oval.AsShort
);
RegisterMapping<byte>(
(mapper, value) => new ODBInteger(value),
(mapper, oval) => oval.AsByte
);
RegisterMapping<uint>(
(mapper, value) => new ODBUInteger(value),
(mapper, oval) => oval.AsUInt
);
RegisterMapping<ushort>(
(mapper, value) => new ODBUInteger(value),
(mapper, oval) => oval.AsUShort
);
RegisterMapping<char>(
(mapper, value) => new ODBUInteger(value),
(mapper, oval) => oval.AsChar
);
RegisterMapping<double>(
(mapper, value) => new ODBDouble(value),
(mapper, oval) => oval.AsDouble
);
RegisterMapping<float>(
(mapper, value) => new ODBDouble(value),
(mapper, oval) => oval.AsFloat
);
RegisterMapping<DateTime>(
(mapper, value) => new ODBLong(DateTime.MinValue.Equals(value) ? 0 : new DateTimeOffset(value).ToUnixTimeMilliseconds() ),
(mapper, oval) => DateTimeOffset.FromUnixTimeMilliseconds(oval.AsLong).DateTime
);
RegisterMapping<TimeSpan>(
(mapper, value) => new ODBDouble(value.TotalMilliseconds),
(mapper, oval) => TimeSpan.FromMilliseconds(oval.AsDouble)
);
RegisterMapping<Guid>(
(mapper, value) => new ODBGuid(value),
(mapper, oval) => oval.AsGuid
);
RegisterMapping<long>(
(mapper, value) => new ODBLong(value),
(mapper, oval) => oval.AsLong
);
RegisterMapping<ulong>(
(mapper, value) => new ODBULong(value),
(mapper, oval) => oval.AsULong
);
RegisterMapping<bool>(
(mapper, value) => new ODBInteger(value ? -1 : 0),
(mapper, oval) => oval.AsBool
);
RegisterMapping(typeof(object),new ObjectMapping());
}
public void RegisterMapping(Type nativeType,IODBMapping mapping)
{
mappings[nativeType] = mapping;
}
public void RegisterMapping(Type nativeType, ODBMap map, ODBUnmap unmap)
{
mappings[nativeType] = new SimpleMapping(map, unmap);
}
public void RegisterMapping<T>(ODBMap<T> map, ODBUnmap<T> unmap)
{
mappings[typeof(T)] = new SimpleMapping<T>(map, unmap);
}
public IODBMapping GetMapping<T>() => null;
public IODBMapping GetMapping(Type type)
{
if (mappings.ContainsKey(type))
return mappings[type];
if (typeof(string).Equals(type))
{
return null;
}
else if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Dictionary<,>)))
{
mappings.Add(type, new DictionaryMapping());
return mappings[type];
}
else if (type.GetInterfaces().Contains(typeof(IDictionary)))
{
mappings.Add(type, new DictionaryMapping());
return mappings[type];
}
else if (type.IsArray)
{
mappings.Add(type, new ListMapping(type));
return mappings[type];
}
else if (!type.IsPrimitive)
{
mappings.Add(type, new ClassMapping(type));
return mappings[type];
}
return null;
}
public virtual ODBValue MapValue(object value)
{
if (value == null)
return ODBNull.Instance;
IODBMapping mapping = GetMapping(value.GetType());
if (mapping != null)
return mappings[value.GetType()].MapValue(this,value);
throw new NotSupportedException(String.Format("Can't map {0} ({1})",value.GetType(),value));
}
public virtual object UnmapValue(Type targetType,ODBValue value)
{
if (ODBNull.Instance.Equals(value))
return null;
if (value is ODBDocument)
{
ODBDocument doc = value as ODBDocument;
String asmname = doc["__asm__"].AsString;
String typename = doc["__type__"].AsString;
targetType = Assembly.Load(asmname).GetType(typename);
}
IODBMapping mapping = GetMapping(targetType);
if (mapping != null)
return mappings[targetType].UnmapValue(this,value);
return Convert.ChangeType(value.Value, targetType);
}
public virtual T ToNativeValue<T>(ODBValue value)
{
return (T)UnmapValue(typeof(T), value);
}
}
}

View File

@ -12,26 +12,26 @@ using System.IO;
using ln.types.serialize;
namespace ln.types.odb
{
public class ODBObjectReader : ObjectReader
{
public ODB ODB { get; }
//public class ODBObjectReader : ObjectReader
//{
// public ODB ODB { get; }
public ODBObjectReader(ODB odb, Stream stream) :
base(stream)
{
ODB = odb;
}
// public ODBObjectReader(ODB odb, Stream stream) :
// base(stream)
// {
// ODB = odb;
// }
public override object QueryReferencedObject(object re)
{
if (re is Guid)
{
Guid persistenceID = (Guid)re;
IPersistent persistent = ODB.LoadPersistent(persistenceID);
return persistent;
}
// public override object QueryReferencedObject(object re)
// {
// if (re is Guid)
// {
// Guid persistenceID = (Guid)re;
// IPersistent persistent = ODB.LoadPersistent(persistenceID);
// return persistent;
// }
return base.QueryReferencedObject(re);
}
}
// return base.QueryReferencedObject(re);
// }
//}
}

View File

@ -14,30 +14,30 @@ using ln.types.serialize;
using System.Linq;
namespace ln.types.odb
{
class ODBObjectWriter : ObjectWriter
{
public IPersistent[] ReferencedPersistents => referencedPersistents.Values.ToArray();
public Guid[] ReferencedPersistentIDs => referencedPersistents.Keys.ToArray();
//class ODBObjectWriter : ObjectWriter
//{
// public IPersistent[] ReferencedPersistents => referencedPersistents.Values.ToArray();
// public Guid[] ReferencedPersistentIDs => referencedPersistents.Keys.ToArray();
private Dictionary<Guid, IPersistent> referencedPersistents = new Dictionary<Guid, IPersistent>();
// private Dictionary<Guid, IPersistent> referencedPersistents = new Dictionary<Guid, IPersistent>();
public ODBObjectWriter(Stream stream)
: base(stream)
{}
// public ODBObjectWriter(Stream stream)
// : base(stream)
// {}
public override object QueryReference(object o)
{
if (o is IPersistent)
{
IPersistent persistent = o as IPersistent;
Guid persistenceID = persistent.GetPersistenceID();
// public override object QueryReference(object o)
// {
// if (o is IPersistent)
// {
// IPersistent persistent = o as IPersistent;
// Guid persistenceID = persistent.GetPersistenceID();
if (!referencedPersistents.ContainsKey(persistenceID))
referencedPersistents.Add(persistenceID, persistent);
// if (!referencedPersistents.ContainsKey(persistenceID))
// referencedPersistents.Add(persistenceID, persistent);
return persistenceID;
}
return base.QueryReference(o);
}
}
// return persistenceID;
// }
// return base.QueryReference(o);
// }
//}
}

View File

@ -8,10 +8,12 @@
// *
// **/
using System;
using LiteDB;
namespace ln.types.odb
{
public class Persistent : IPersistent
{
[BsonId]
public Guid PersistenceID { get; private set; }
public Persistent()

View File

@ -3,163 +3,163 @@ using System.Collections;
using System.Collections.Generic;
namespace ln.types.odb
{
public class PersistentList<T> : IList<T> where T: IPersistent
{
private Dictionary<Guid, T> persistentInstances = new Dictionary<Guid, T>();
private List<Guid> index = new List<Guid>();
//public class PersistentList<T> : IList<T> where T: IPersistent
//{
// private Dictionary<Guid, T> persistentInstances = new Dictionary<Guid, T>();
// private List<Guid> index = new List<Guid>();
public ODB ODB { get; }
// public ODB ODB { get; }
public PersistentList(ODB odb)
{
ODB = odb;
}
// public PersistentList(ODB odb)
// {
// ODB = odb;
// }
public T this[int n]
{
get {
Guid persistentID = index[n];
if (!persistentInstances.ContainsKey(persistentID))
persistentInstances[persistentID] = (T)ODB.LoadPersistent(persistentID);
// public T this[int n]
// {
// get {
// Guid persistentID = index[n];
// if (!persistentInstances.ContainsKey(persistentID))
// persistentInstances[persistentID] = (T)ODB.LoadPersistent(persistentID);
return persistentInstances[persistentID];
}
set {
if (value == null)
index[n] = Guid.Empty;
// return persistentInstances[persistentID];
// }
// set {
// if (value == null)
// index[n] = Guid.Empty;
Guid persistenceID = value.GetPersistenceID();
persistentInstances[persistenceID] = value;
index[n] = persistenceID;
}
}
// Guid persistenceID = value.GetPersistenceID();
// persistentInstances[persistenceID] = value;
// index[n] = persistenceID;
// }
// }
public int Count => index.Count;
public bool IsReadOnly => false;
// public int Count => index.Count;
// public bool IsReadOnly => false;
public void Add(T item)
{
if (item == null)
{
index.Add(Guid.Empty);
}
else
{
Guid persistenceID = item.GetPersistenceID();
persistentInstances[persistenceID] = item;
index.Add(persistenceID);
}
}
// public void Add(T item)
// {
// if (item == null)
// {
// index.Add(Guid.Empty);
// }
// else
// {
// Guid persistenceID = item.GetPersistenceID();
// persistentInstances[persistenceID] = item;
// index.Add(persistenceID);
// }
// }
public void Clear()
{
persistentInstances.Clear();
index.Clear();
}
// public void Clear()
// {
// persistentInstances.Clear();
// index.Clear();
// }
public bool Contains(T item)
{
Guid persistenceID = item.GetPersistenceID();
if (index.Contains(persistenceID))
return true;
// public bool Contains(T item)
// {
// Guid persistenceID = item.GetPersistenceID();
// if (index.Contains(persistenceID))
// return true;
foreach (T mine in this)
{
if (mine.Equals(item))
return true;
}
return false;
}
// foreach (T mine in this)
// {
// if (mine.Equals(item))
// return true;
// }
// return false;
// }
public void CopyTo(T[] array, int arrayIndex)
{
foreach (T item in this)
{
array[arrayIndex] = this[arrayIndex];
arrayIndex++;
}
}
// public void CopyTo(T[] array, int arrayIndex)
// {
// foreach (T item in this)
// {
// array[arrayIndex] = this[arrayIndex];
// arrayIndex++;
// }
// }
public IEnumerator<T> GetEnumerator()
{
return new PersistentListEnumerator(this);
}
// public IEnumerator<T> GetEnumerator()
// {
// return new PersistentListEnumerator(this);
// }
public int IndexOf(T item)
{
Guid persistenceID = item == null ? Guid.Empty : item.GetPersistenceID();
// public int IndexOf(T item)
// {
// Guid persistenceID = item == null ? Guid.Empty : item.GetPersistenceID();
int i = index.IndexOf(persistenceID);
if (i < 0)
{
for (int n=0;n<Count;n++)
{
if (this[n].Equals(item))
return n;
}
}
return -1;
}
// int i = index.IndexOf(persistenceID);
// if (i < 0)
// {
// for (int n=0;n<Count;n++)
// {
// if (this[n].Equals(item))
// return n;
// }
// }
// return -1;
// }
public void Insert(int _index, T item)
{
Guid persistenceID = item == null ? Guid.Empty : item.GetPersistenceID();
index.Insert(_index, persistenceID);
persistentInstances[persistenceID] = item;
}
// public void Insert(int _index, T item)
// {
// Guid persistenceID = item == null ? Guid.Empty : item.GetPersistenceID();
// index.Insert(_index, persistenceID);
// persistentInstances[persistenceID] = item;
// }
public bool Remove(T item)
{
int ind = IndexOf(item);
if (ind >= 0)
RemoveAt(ind);
// public bool Remove(T item)
// {
// int ind = IndexOf(item);
// if (ind >= 0)
// RemoveAt(ind);
return ind >= 0;
}
// return ind >= 0;
// }
public void RemoveAt(int _index)
{
Guid persistenceID = index[_index];
if (persistentInstances.ContainsKey(persistenceID))
persistentInstances.Remove(persistenceID);
index.RemoveAt(_index);
}
// public void RemoveAt(int _index)
// {
// Guid persistenceID = index[_index];
// if (persistentInstances.ContainsKey(persistenceID))
// persistentInstances.Remove(persistenceID);
// index.RemoveAt(_index);
// }
IEnumerator IEnumerable.GetEnumerator()
{
return new PersistentListEnumerator(this);
}
// IEnumerator IEnumerable.GetEnumerator()
// {
// return new PersistentListEnumerator(this);
// }
class PersistentListEnumerator : IEnumerator<T>
{
int currentIndex = -1;
PersistentList<T> persistentList;
// class PersistentListEnumerator : IEnumerator<T>
// {
// int currentIndex = -1;
// PersistentList<T> persistentList;
public PersistentListEnumerator(PersistentList<T> persistentList)
{
this.persistentList = persistentList;
}
// public PersistentListEnumerator(PersistentList<T> persistentList)
// {
// this.persistentList = persistentList;
// }
public T Current => persistentList[currentIndex];
object IEnumerator.Current => persistentList[currentIndex];
// public T Current => persistentList[currentIndex];
// object IEnumerator.Current => persistentList[currentIndex];
public void Dispose()
{
persistentList = null;
}
// public void Dispose()
// {
// persistentList = null;
// }
public bool MoveNext()
{
currentIndex++;
return (currentIndex < persistentList.Count);
}
// public bool MoveNext()
// {
// currentIndex++;
// return (currentIndex < persistentList.Count);
// }
public void Reset()
{
currentIndex = -1;
}
}
// public void Reset()
// {
// currentIndex = -1;
// }
// }
}
//}
}

View File

@ -13,171 +13,169 @@ using System.CodeDom;
using System.Reflection;
using System.IO;
using System.Linq;
using ln.types.sync;
namespace ln.types.odb
{
public class PreparedObject
{
public ODB ODB { get; private set; }
//public class PreparedObject
//{
// public ODB ODB { get; private set; }
public DateTime Timestamp { get; private set; }
public Type PreparedType { get; private set; }
// public DateTime Timestamp { get; private set; }
// public Type PreparedType { get; private set; }
public IPersistent Instance { get; set; }
public Guid PersistenceID { get; private set; }
// public IPersistent Instance { get; set; }
// public Guid PersistenceID { get; private set; }
public string[] StoredFieldNames => fieldStore.Keys.ToArray();
// public string[] StoredFieldNames => fieldStore.Keys.ToArray();
public IEnumerable<Guid> ReferencedPersistentIDs => referencedPersistentIDs;
public IEnumerable<IPersistent> ReferencedPersistents => referencedPersistents;
// public IEnumerable<Guid> ReferencedPersistentIDs => referencedPersistentIDs;
// public IEnumerable<IPersistent> ReferencedPersistents => referencedPersistents;
List<Guid> referencedPersistentIDs = new List<Guid>();
HashSet<IPersistent> referencedPersistents = new HashSet<IPersistent>();
Dictionary<string, byte[]> fieldStore = new Dictionary<string, byte[]>();
// List<Guid> referencedPersistentIDs = new List<Guid>();
// HashSet<IPersistent> referencedPersistents = new HashSet<IPersistent>();
// Dictionary<string, byte[]> fieldStore = new Dictionary<string, byte[]>();
public PreparedObject(ODB odb,Type preparedType,Guid persistenceID)
{
ODB = odb;
Timestamp = DateTime.Now;
PreparedType = preparedType;
PersistenceID = persistenceID;
Instance = null;
}
public PreparedObject(ODB odb, IPersistent o)
{
ODB = odb;
Timestamp = DateTime.Now;
PreparedType = o.GetType();
PersistenceID = o.GetPersistenceID();
Instance = o;
// public PreparedObject(ODB odb,Type preparedType,Guid persistenceID)
// {
// ODB = odb;
// Timestamp = DateTime.Now;
// PreparedType = preparedType;
// PersistenceID = persistenceID;
// Instance = null;
// }
// public PreparedObject(ODB odb, IPersistent o)
// {
// ODB = odb;
// Timestamp = DateTime.Now;
// PreparedType = o.GetType();
// PersistenceID = o.GetPersistenceID();
// Instance = o;
SyncFromInstance();
}
// SyncFromInstance();
// }
private IEnumerable<FieldInfo> GetAllFields(Type type)
{
if (type == typeof(object))
{
return new FieldInfo[0];
}
else
{
return GetAllFields(type.BaseType).Concat(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly));
}
}
// private IEnumerable<FieldInfo> GetAllFields(Type type)
// {
// if (type == typeof(object))
// {
// return new FieldInfo[0];
// }
// else
// {
// return GetAllFields(type.BaseType).Concat(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly));
// }
// }
private void SyncFromInstance()
{
referencedPersistentIDs.Clear();
FieldInfo[] fields = GetAllFields(PreparedType).ToArray();
// public void SyncFromInstance()
// {
// referencedPersistentIDs.Clear();
// FieldInfo[] fields = GetAllFields(PreparedType).ToArray();
foreach (FieldInfo fieldInfo in fields)
{
if (!fieldInfo.IsStatic)
{
object value = fieldInfo.GetValue(Instance);
if (value == null)
{
fieldStore[fieldInfo.Name] = new byte[0];
}
else
{
MemoryStream objectStream = new MemoryStream();
ODBObjectWriter objectWriter = new ODBObjectWriter(objectStream);
// foreach (FieldInfo fieldInfo in fields)
// {
// if (!fieldInfo.IsStatic && (fieldInfo.GetCustomAttribute<Unsynced>() == null))
// {
// object value = fieldInfo.GetValue(Instance);
// if (value == null)
// {
// fieldStore[fieldInfo.Name] = new byte[0];
// }
// else
// {
// MemoryStream objectStream = new MemoryStream();
// ODBObjectWriter objectWriter = new ODBObjectWriter(objectStream);
objectWriter.Write(value);
// objectWriter.Write(value);
fieldStore[fieldInfo.Name] = objectStream.ToArray();
referencedPersistentIDs.AddRange(objectWriter.ReferencedPersistentIDs);
foreach (IPersistent persistent in objectWriter.ReferencedPersistents)
referencedPersistents.Add(persistent);
}
}
}
}
private void SyncToInstance()
{
foreach (FieldInfo fieldInfo in GetAllFields(PreparedType))
{
if (!fieldInfo.IsStatic)
{
byte[] bytes = fieldStore[fieldInfo.Name];
if (bytes.Length == 0)
{
fieldInfo.SetValue(Instance, null);
}
else
{
MemoryStream objectStream = new MemoryStream(fieldStore[fieldInfo.Name]);
ODBObjectReader objectReader = new ODBObjectReader(ODB, objectStream);
// fieldStore[fieldInfo.Name] = objectStream.ToArray();
// referencedPersistentIDs.AddRange(objectWriter.ReferencedPersistentIDs);
// foreach (IPersistent persistent in objectWriter.ReferencedPersistents)
// referencedPersistents.Add(persistent);
// }
// }
// }
// }
// public void SyncToInstance()
// {
// foreach (FieldInfo fieldInfo in GetAllFields(PreparedType))
// {
// if (!fieldInfo.IsStatic && (fieldInfo.GetCustomAttribute<Unsynced>() == null))
// {
// byte[] bytes = fieldStore[fieldInfo.Name];
// if (bytes.Length == 0)
// {
// fieldInfo.SetValue(Instance, null);
// }
// else
// {
// MemoryStream objectStream = new MemoryStream(fieldStore[fieldInfo.Name]);
// ODBObjectReader objectReader = new ODBObjectReader(ODB, objectStream);
object value = objectReader.Read();
fieldInfo.SetValue(Instance, value);
}
}
}
}
// object value = objectReader.Read();
// fieldInfo.SetValue(Instance, value);
// }
// }
// }
// }
public void ReConfigure(Type targetType,DateTime timestamp)
{
Timestamp = timestamp;
PreparedType = targetType;
fieldStore.Clear();
Instance = null;
}
// public void ReConfigure(Type targetType,DateTime timestamp)
// {
// Timestamp = timestamp;
// PreparedType = targetType;
// fieldStore.Clear();
// Instance = null;
// }
public byte[] GetFieldBytes(string fieldName)
{
return fieldStore[fieldName];
}
public void SetFieldBytes(string fieldName,byte[] bytes)
{
fieldStore[fieldName] = bytes;
}
// public byte[] GetFieldBytes(string fieldName)
// {
// return fieldStore[fieldName];
// }
// public void SetFieldBytes(string fieldName,byte[] bytes)
// {
// fieldStore[fieldName] = bytes;
// }
public IPersistent CreateInstance()
{
Instance = (IPersistent)Activator.CreateInstance(PreparedType,true);
SyncToInstance();
return Instance;
}
// public IPersistent CreateInstance()
// {
// Instance = (IPersistent)Activator.CreateInstance(PreparedType,true);
// SyncToInstance();
// return Instance;
// }
public bool InstanceEquals(PreparedObject other)
{
if (other == null)
return false;
// public bool InstanceEquals(PreparedObject other)
// {
// if (other == null)
// return false;
if (Equals(other))
{
foreach (String fieldName in fieldStore.Keys)
{
byte[] me = fieldStore[fieldName];
byte[] you = other.fieldStore[fieldName];
// if (Equals(other))
// {
// foreach (String fieldName in fieldStore.Keys)
// {
// byte[] me = fieldStore[fieldName];
// byte[] you = other.fieldStore[fieldName];
File.WriteAllBytes("me.bin", me);
File.WriteAllBytes("you.bin", you);
// if (!me.AreEqual(you))
// return false;
// }
// return true;
// }
// return false;
// }
if (!me.AreEqual(you))
return false;
}
return true;
}
return false;
}
// public override int GetHashCode()
// {
// return PersistenceID.GetHashCode() ^ PreparedType.GetHashCode();
// }
public override int GetHashCode()
{
return PersistenceID.GetHashCode() ^ PreparedType.GetHashCode();
}
// public override bool Equals(object obj)
// {
// if (obj is PreparedObject)
// {
// PreparedObject you = obj as PreparedObject;
// return PreparedType.Equals(you.PreparedType) && PersistenceID.Equals(you.PersistenceID);
// }
// return false;
// }
public override bool Equals(object obj)
{
if (obj is PreparedObject)
{
PreparedObject you = obj as PreparedObject;
return PreparedType.Equals(you.PreparedType) && PersistenceID.Equals(you.PersistenceID);
}
return false;
}
}
//}
}

View File

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

View File

@ -0,0 +1,28 @@
using System;
namespace ln.types.odb.values
{
public class ODBDouble : ODBValue
{
public ODBDouble()
:base(0x18)
{
}
public ODBDouble(double value)
: this()
{
Value = value;
}
public override byte[] ToStorage()
{
return BitConverter.GetBytes(AsDouble);
}
static ODBDouble()
{
RegisterDeserializer(0x0018, (b, o, l) => BitConverter.ToDouble(b, o));
//RegisterValueFactory(typeof(double), v => new ODBDouble((double)v));
//RegisterValueFactory(typeof(float), v => new ODBDouble((double)v));
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Linq;
namespace ln.types.odb.values
{
public class ODBGuid : ODBValue
{
public ODBGuid()
:base(0x03)
{
Value = Guid.NewGuid();
}
public ODBGuid(Guid guid)
:this()
{
Value = guid;
}
public override byte[] ToStorage()
{
return AsGuid.ToByteArray();
}
static Guid FromByteArray(byte[] b,int offset)
{
byte[] s = new byte[16];
Array.Copy(b, offset, s, 0, 16);
return new Guid(s);
}
static ODBGuid()
{
RegisterDeserializer(0x03, (b,o,l) => FromByteArray(b,o));
}
}
}

View File

@ -0,0 +1,53 @@
using System;
using System.Runtime.CompilerServices;
namespace ln.types.odb.values
{
public class ODBInteger : ODBValue
{
public ODBInteger()
: base(0x10)
{
}
public ODBInteger(int i)
: this()
{
Value = i;
}
public override bool AsBool => AsInt != 0;
public override byte[] ToStorage() => BitConverter.GetBytes(AsInt);
static ODBInteger()
{
RegisterDeserializer(0x10, (b, o, l) => BitConverter.ToInt32(b, o));
//RegisterValueFactory(typeof(int), v => new ODBInteger((int)v));
//RegisterValueFactory(typeof(short), v => new ODBInteger((int)(short)v));
//RegisterValueFactory(typeof(byte), v => new ODBInteger((int)(byte)v));
}
}
public class ODBUInteger : ODBValue
{
public ODBUInteger()
: base(0x11)
{
}
public ODBUInteger(uint i)
: this()
{
Value = i;
}
public override byte[] ToStorage() => BitConverter.GetBytes(AsUInt);
static ODBUInteger()
{
RegisterDeserializer(0x11, (b, o, l) => BitConverter.ToUInt32(b, o));
//RegisterValueFactory(typeof(uint), v => new ODBUInteger((uint)v));
//RegisterValueFactory(typeof(ushort), v => new ODBUInteger((uint)(ushort)v));
//RegisterValueFactory(typeof(char), v => new ODBUInteger((uint)(char)v));
}
}
}

View File

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Collections;
using System.Runtime.CompilerServices;
namespace ln.types.odb.values
{
public class ODBList : ODBValue
{
List<ODBValue> items = new List<ODBValue>();
public ODBList()
:base(0x02)
{
}
public ODBList(byte[] bytes,int offset,int length)
:this()
{
MemoryStream stream = new MemoryStream(bytes, offset, length);
int nItems = stream.ReadInteger();
for (int n = 0; n < nItems; n++)
items.Add(ODBValue.Read(stream));
}
public ODBValue this[int i]
{
get => items[i];
set => items[i] = value;
}
public void Add(ODBValue value)
{
items.Add(value);
}
public void Remove(ODBValue value)
{
items.Remove(value);
}
public void RemoveAt(int i)
{
items.RemoveAt(i);
}
public int Count => items.Count;
public override object Value {
get
{
object[] a = new object[items.Count];
((IList)items).CopyTo(a, 0);
return a;
}
protected set
{
throw new NotSupportedException();
}
}
public override byte[] ToStorage()
{
MemoryStream stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(items.Count);
foreach (ODBValue value in items)
value.Store(writer);
return stream.ToArray();
}
static ODBList()
{
RegisterDeserializer(0x02, (b, o, l) => new ODBList(b,o,l));
}
}
}

View File

@ -0,0 +1,52 @@
using System;
using System.Runtime.CompilerServices;
namespace ln.types.odb.values
{
public class ODBLong : ODBValue
{
public ODBLong()
: base(0x12)
{
}
public ODBLong(long i)
: this()
{
Value = i;
}
public override byte[] ToStorage() => BitConverter.GetBytes(AsLong);
public override DateTime AsDateTime => DateTimeOffset.FromUnixTimeMilliseconds(AsLong).DateTime;
public override TimeSpan AsTimeSpan => TimeSpan.FromMilliseconds(AsDouble);
static ODBLong()
{
RegisterDeserializer(0x12, (b, o, l) => BitConverter.ToInt64(b, o));
//RegisterValueFactory(typeof(long), v => new ODBLong((long)v));
//RegisterValueFactory(typeof(DateTime), v => new ODBLong(new DateTimeOffset((DateTime)v).ToUnixTimeMilliseconds()));
}
}
public class ODBULong : ODBValue
{
public ODBULong()
: base(0x13)
{
}
public ODBULong(ulong i)
: this()
{
Value = i;
}
public override byte[] ToStorage() => BitConverter.GetBytes(AsULong);
static ODBULong()
{
RegisterDeserializer(0x13, (b, o, l) => BitConverter.ToUInt64(b, o));
//RegisterValueFactory(typeof(ulong), v => new ODBULong((ulong)v));
}
}
}

View File

@ -0,0 +1,32 @@
using System;
namespace ln.types.odb.values
{
public class ODBNull : ODBValue
{
public static readonly ODBNull Instance = new ODBNull();
public ODBNull()
: base(0x00)
{ }
public override byte[] ToStorage()
{
return new byte[0];
}
static ODBNull()
{
RegisterDeserializer(0x00, (b,o,l) => Instance);
}
public override int GetHashCode()
{
return 0;
}
public override bool Equals(object obj)
{
return (obj == null) || (obj is ODBNull);
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Text;
namespace ln.types.odb.values
{
public class ODBStringValue : ODBValue
{
public ODBStringValue()
: base(0x01)
{ }
public ODBStringValue(String text)
: this()
{
Value = text;
}
public override byte[] ToStorage()
{
return Encoding.UTF8.GetBytes(AsString);
}
public static implicit operator ODBStringValue(String text)
{
return new ODBStringValue(text);
}
static ODBStringValue()
{
RegisterDeserializer(0x01, (b, o, l) => new ODBStringValue(Encoding.UTF8.GetString(b, o, l)));
// RegisterValueFactory(typeof(string), v => new ODBStringValue((string)v));
}
}
}

View File

@ -0,0 +1,150 @@
using System;
using System.Collections.Generic;
using System.IO;
/**
* typeCode list
*
* 0x0000 ODBNull
* 0x0001 ODBStringValue
* 0x0002 ODBList
* 0x0003 ODBGuid
*
* 0x0010 ODBInteger
* 0x0011 ODBUInteger
* 0x0012 ODBLong
* 0x0013 ODBULong
*
* 0x0018 ODBDouble
*
* 0x1000 ODBDocument
*
*
*
**/
namespace ln.types.odb.values
{
public delegate ODBValue ODBValueFactory(object value);
public delegate ODBValue ODBDeserialize(byte[] storageBytes, int offset, int length);
public abstract class ODBValue
{
int storageTypeCode;
public virtual object Value { get; protected set; }
protected ODBValue(int storageTypeCode)
{
this.storageTypeCode = storageTypeCode;
}
protected ODBValue(int storageTypeCode, object value)
: this(storageTypeCode)
{
Value = value;
}
public abstract byte[] ToStorage();
public object AsObject => Value;
public virtual string AsString => (string)Value;
public virtual bool AsBool => (bool)Value;
public virtual byte AsByte => (byte)Value;
public virtual char AsChar => (char)Value;
public virtual short AsShort => (short)Value;
public virtual int AsInt => (int)Value;
public virtual long AsLong => (long)Value;
public virtual ushort AsUShort => (ushort)Value;
public virtual uint AsUInt => (uint)Value;
public virtual ulong AsULong => (ulong)Value;
public virtual double AsDouble => (double)Value;
public virtual float AsFloat => (float)Value;
public virtual Guid AsGuid => (Guid)Value;
public virtual DateTime AsDateTime => (DateTime)Value;
public virtual TimeSpan AsTimeSpan => (TimeSpan)Value;
public virtual ODBDocument AsDocument => (ODBDocument)this;
public virtual void Store(BinaryWriter storage)
{
byte[] storageBytes = ToStorage();
storage.Write(storageTypeCode);
storage.Write(storageBytes.Length);
storage.Write(storageBytes, 0, storageBytes.Length);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj is ODBValue)
{
ODBValue you = obj as ODBValue;
return Value.Equals(you.Value);
}
return Value.Equals(obj);
}
//static Dictionary<Type, ODBValueFactory> valueFactories = new Dictionary<Type, ODBValueFactory>();
//public static void RegisterValueFactory(Type type, ODBValueFactory factory)
//{
// valueFactories.Add(type, factory);
//}
public static implicit operator ODBValue(ValueType v)
{
return ODBMapper.Default.MapValue(v);
}
public static implicit operator ODBValue(String v)
{
return ODBMapper.Default.MapValue(v);
}
public static ODBValue FromNative(object v)
{
return ODBMapper.Default.MapValue(v);
}
static Dictionary<int, ODBDeserialize> valueDeserializers = new Dictionary<int, ODBDeserialize>();
public static void RegisterDeserializer(int storageTypeCode, ODBDeserialize deserialize)
{
valueDeserializers.Add(storageTypeCode, deserialize);
}
public static ODBValue Deserialize(byte[] buffer, ref int offset)
{
int storageTypeCode = BitConverter.ToInt32(buffer, offset);
int storageLength = BitConverter.ToInt32(buffer, offset + 4);
ODBValue value = valueDeserializers[storageTypeCode](buffer, offset + 8, storageLength);
offset += 8 + storageLength;
return value;
}
public static ODBValue Read(Stream stream)
{
int storageTypeCode = stream.ReadInteger();
int storageLength = stream.ReadInteger();
byte[] b = new byte[storageLength];
stream.Read(b, 0, storageLength);
return valueDeserializers[storageTypeCode](b, 0, storageLength);
}
public override string ToString()
{
return String.Format("[ODBValue Value={0}]", Value);
}
}
}

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Castle.Core" version="4.3.1" targetFramework="net47" />
<package id="LiteDB" version="4.1.4" targetFramework="net47" />
<package id="Newtonsoft.Json" version="12.0.1" targetFramework="net47" />
</packages>

View File

@ -182,6 +182,7 @@ namespace ln.types.serialize
public object ReadObject()
{
Type type = Read<Type>();
object o = Activator.CreateInstance(type,true);
referencedObjects.Add(o);

View File

@ -214,33 +214,38 @@ namespace ln.types.threads
{
supervisorThread = Thread.CurrentThread;
while (CurrentPoolSize > 0)
lock (supervisorThread)
{
while (CurrentPoolSize != TargetPoolSize)
{
if (CurrentPoolSize - TargetPoolSize > 0)
{
lock (queuedJobs)
{
releaseThreads = CurrentPoolSize - TargetPoolSize;
}
while (CurrentPoolSize > 0)
{
Monitor.Wait(supervisorThread, 1000);
while (CurrentPoolSize != TargetPoolSize)
{
if (CurrentPoolSize - TargetPoolSize > 0)
{
lock (queuedJobs)
{
Monitor.PulseAll(queuedJobs);
releaseThreads = CurrentPoolSize - TargetPoolSize;
}
if (CurrentPoolSize - TargetPoolSize > 0)
{
lock (queuedJobs)
{
Monitor.PulseAll(queuedJobs);
}
}
}
}
else if (CurrentPoolSize - TargetPoolSize < 0)
{
for (int n = CurrentPoolSize; n < TargetPoolSize; n++)
new PoolThread(this);
else if (CurrentPoolSize - TargetPoolSize < 0)
{
for (int n = CurrentPoolSize; n < TargetPoolSize; n++)
new PoolThread(this);
}
}
}
}
supervisorThread = null;
}