From aebc6df9aba6aa403b66ce3eb8f8c32ade28b96d Mon Sep 17 00:00:00 2001 From: Harald Wolff Date: Fri, 29 Mar 2019 08:55:17 +0100 Subject: [PATCH] WIP --- BTree.cs | 186 -------- CIDR.cs | 2 +- btree/BTree.cs | 411 ++++++++++++++++++ btree/MappingBTree.cs | 53 +++ ln.types.csproj | 11 +- odb/ODB.cs | 16 +- ...ection.DocumentIndex.DocumentIndexEntry.cs | 236 +--------- odb/ODBCollection.DocumentIndex.cs | 171 ++++++-- odb/ODBCollection.cs | 169 ++++--- odb/ODBCollection<>.cs | 49 ++- odb/ODBDocument.cs | 12 + odb/PropertyIndex.cs | 63 +++ odb/values/ODBBool.cs | 10 + odb/values/ODBDouble.cs | 14 + odb/values/ODBGuid.cs | 7 + odb/values/ODBInteger.cs | 19 + odb/values/ODBList.cs | 8 + odb/values/ODBLong.cs | 29 ++ odb/values/ODBNull.cs | 7 + odb/values/ODBStringValue.cs | 7 + odb/values/ODBValue.cs | 16 + test/testODB.cs | 153 +++++++ threads/Timing.cs | 47 ++ 23 files changed, 1192 insertions(+), 504 deletions(-) delete mode 100644 BTree.cs create mode 100644 btree/BTree.cs create mode 100644 btree/MappingBTree.cs create mode 100644 odb/PropertyIndex.cs create mode 100644 test/testODB.cs create mode 100644 threads/Timing.cs diff --git a/BTree.cs b/BTree.cs deleted file mode 100644 index 9d88817..0000000 --- a/BTree.cs +++ /dev/null @@ -1,186 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -namespace ln.types -{ - public class BTree : IEnumerable - { - public Comparison Comparison { get; } - private TreeNode headNode; - - public BTree() - { - if (!typeof(T).GetInterfaces().Contains(typeof(IComparable))) - throw new ArgumentException("BTree need to be constructed with Comparer if T is not providing IComparable"); - - Comparison = (T x, T y) => ((IComparable)x).CompareTo(y); - } - public BTree(Comparison comparison) - { - Comparison = comparison; - } - - public void Add(T element) - { - } - public void Remove(T element) - { - } - public bool Contains(T element) - { - return false; - } - - private TreeNode First() - { - if (headNode == null) - return null; - return headNode.First(); - } - private TreeNode Last() - { - if (headNode == null) - return null; - return headNode.Last(); - } - - public IEnumerator GetEnumerator() - { - TreeNode node = First(); - while (node != null) - { - yield return node.Value; - node = node.Next(); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public class TreeNode - { - public BTree Tree { get; } - - public NT Value { get; set; } - - public TreeNode Parent { get; private set; } - public int Depth => 1 + (leftDepth > rightDepth ? leftDepth : rightDepth); - - private TreeNode left; - private TreeNode right; - - private int leftDepth; - private int rightDepth; - - - - public TreeNode(BTree tree) - { - Tree = tree; - } - - public TreeNode(BTree tree,NT value) - :this(tree) - { - Value = value; - } - - - private void Attach(TreeNode parent) - { - if (this.Parent == null) - Parent = parent; - else - throw new ArgumentException("TreeNode is already attached"); - } - private void Detach(TreeNode parent) - { - if (this.Parent != parent) - Parent = null; - else - throw new ArgumentException("TreeNode is not attached to this parent"); - } - - public TreeNode First() - { - if (Left != null) - return Left.First(); - return this; - } - public TreeNode Last() - { - if (Right != null) - return Left.Last(); - return this; - } - public TreeNode Next() - { - if (Right != null) - return Right.First(); - - if (Parent == null) - return null; - - TreeNode next = Parent; - while (Tree.Comparison(next.Value, this.Value) < 0) - next = next.Parent; - return next; - } - - public TreeNode Left - { - get => left; - set - { - if (value == null) - { - if (left != null) - { - left.Detach(this); - leftDepth = 0; - } - } - else - { - if (left != null) - throw new ArgumentException("There is already a TreeNode attached to the left."); - - value.Attach(this); - left = value; - leftDepth = left.Depth; - } - } - } - public TreeNode Right - { - get => right; - set - { - if (value == null) - { - if (right != null) - { - right.Detach(this); - rightDepth = 0; - } - } - else - { - if (right != null) - throw new ArgumentException("There is already a TreeNode attached to the left."); - - value.Attach(this); - right = value; - rightDepth = right.Depth; - } - } - } - - - } - - } -} diff --git a/CIDR.cs b/CIDR.cs index 9752fc6..346d238 100644 --- a/CIDR.cs +++ b/CIDR.cs @@ -139,8 +139,8 @@ namespace ln.types CIDR[] result = new CIDR[count]; for (int n = 0; n < count; n++) { - nip += (uint)(1 << (32 - MaskWidth - bits)); result[n] = new CIDR(nip, newmask); + nip += (uint)(1 << (32 - MaskWidth - bits)); } return result; } diff --git a/btree/BTree.cs b/btree/BTree.cs new file mode 100644 index 0000000..49b4cd6 --- /dev/null +++ b/btree/BTree.cs @@ -0,0 +1,411 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using ln.types.serialize; +using System.Diagnostics.PerformanceData; +using System.Net.NetworkInformation; + +namespace ln.types.btree +{ + public class BTree + { + public Comparison Comparison { get; } + public int Count => count; + + + TreeNode headNode; + private int count; + + public BTree() + { + if (!typeof(K).GetInterfaces().Contains(typeof(IComparable))) + throw new ArgumentException("BTree need to be constructed with Comparer if T is not providing IComparable"); + + Comparison = (K x, K y) => ((IComparable)x).CompareTo(y); + } + public BTree(Comparison comparison) + { + Comparison = comparison; + } + + public V this[K key] + { + get + { + TreeNode node = Find(key); + if (node == null) + throw new KeyNotFoundException(); + return node.Value; + } + set + { + TreeNode node = Find(key); + if (node == null) + { + Add(key, value); + } + else + { + node.Value = value; + } + } + } + + public void Add(K key,V value) + { + TreeNode treeNode = new TreeNode(this, key, value); + Insert(treeNode); + count++; + } + public void Remove(K key) + { + TreeNode node = Find(key); + if (node == null) + throw new KeyNotFoundException(); + + Remove(node); + count--; + } + public bool TryRemove(K key) + { + TreeNode node = Find(key); + if (node != null) + Remove(node); + + return node != null; + } + + public bool ContainsKey(K key) + { + return Find(key) != null; + } + public bool ContainsValue(V value) + { + return Values.Contains(value); + } + + public void Clear() + { + headNode = null; + count = 0; + } + + public K First() + { + TreeNode node = First(headNode); + if (node != null) + return node.Key; + throw new KeyNotFoundException("BTree is empty"); + } + public K Last() + { + TreeNode node = Last(headNode); + if (node != null) + return node.Key; + throw new KeyNotFoundException("BTree is empty"); + } + public K Previous(K current) + { + TreeNode node = Previous(Find(current)); + if (node != null) + return node.Key; + throw new KeyNotFoundException(); + } + public K Next(K current) + { + TreeNode node = Next(Find(current)); + if (node != null) + return node.Key; + throw new KeyNotFoundException(); + } + + + + + private TreeNode First(TreeNode node) + { + if (node == null) + return null; + + while (node.Left != null) + node = node.Left; + return node; + } + + private TreeNode Last(TreeNode node) + { + if (node == null) + return null; + + while (node.Right != null) + node = node.Right; + return node; + } + + private TreeNode Find(K key) + { + TreeNode node = headNode; + + while (node != null) + { + int comp = Comparison(key, node.Key); + if (comp == 0) + return node; + else if (comp < 0) + node = node.Left; + else + node = node.Right; + } + return null; + } + + private TreeNode Previous(TreeNode node) + { + if (node.Left != null) + return Last(node.Left); + + while (node != null) + { + if (node.Parent == null) + return null; + + if (node.Parent.Right == node) + return node.Parent; + + node = node.Parent; + } + return null; + } + + private TreeNode Next(TreeNode node) + { + if (node.Right != null) + return First(node.Right); + + while (node != null) + { + if (node.Parent == null) + return null; + + if (node.Parent.Left == node) + return node.Parent; + + node = node.Parent; + } + return null; + } + + private void Insert(TreeNode newNode) + { + if (headNode == null) + { + headNode = newNode; + } + else + { + TreeNode node = headNode; + while (true) + { + int c = Comparison(newNode.Key, node.Key); + if (c == 0) + { + throw new ArgumentException("Key exists"); + } + else if (c < 0) + { + if (node.Left == null) + { + newNode.Attach(node); + Balance(node.Parent); + return; + } + else + node = node.Left; + } + else + { + if (node.Right == null) + { + newNode.Attach(node); + Balance(node.Parent); + return; + } + else + node = node.Right; + } + } + } + } + + private void Remove(TreeNode node) + { + TreeNode p = node.Parent; + + if ((node.Left != null) && (node.Right != null)) + { + TreeNode replace = Last(node.Left); + + node.Detach(); + replace.Attach(p); + node.Left.Attach(replace); + node.Right.Attach(replace); + + Balance(replace); + } else + { + node.Detach(); + if (node.Left != null) + node.Left.Attach(p); + else if (node.Right != null) + node.Right.Attach(p); + + Balance(p); + } + } + + private void RotateRight(TreeNode node) + { + TreeNode l = node.Left; + TreeNode p = node.Parent; + + node.Detach(); + l.Attach(p); + if (l.Right!= null) + l.Right.Attach(node); + node.Attach(l); + } + private void RotateLeft(TreeNode node) + { + TreeNode r = node.Right; + TreeNode p = node.Parent; + + node.Detach(); + r.Attach(p); + if (r.Left != null) + r.Left.Attach(node); + node.Attach(r); + } + + private void Balance(TreeNode node) + { + while (node != null) + { + TreeNode p = node.Parent; + int balance = node.LeftDepth - node.RightDepth; + if (balance < -1) + { + RotateLeft(node); + } + else if (balance > 1) + { + RotateRight(node); + } + node = p; + } + } + + + public IEnumerable Keys + { + get + { + TreeNode node = First(headNode); + while (node != null) + { + yield return node.Key; + node = Next(node); + } + } + } + public IEnumerable Values + { + get + { + TreeNode node = First(headNode); + while (node != null) + { + yield return node.Value; + node = Next(node); + } + } + } + + class TreeNode + { + public BTree Tree { get; } + + public K Key { get; private set; } + public V Value { get; set; } + + public TreeNode Parent { get; private set; } + + public int Depth => 1 + Math.Max(LeftDepth, RightDepth); + + public int LeftDepth => Left != null ? Left.Depth : 0; + public int RightDepth => Right != null ? Right.Depth : 0; + + public TreeNode Left { get; private set; } + public TreeNode Right { get; private set; } + + public TreeNode(BTree tree, K key, V value) + { + Tree = tree; + Key = key; + Value = value; + } + + public void Attach(TreeNode parent) + { + if (this.Parent != null) + Detach(); + + if (parent == null) + { + Tree.headNode = this; + Parent = null; + } + else + { + + int comp = Tree.Comparison(Key, parent.Key); + if (comp == 0) + throw new ArgumentException(String.Format("Key already exists in BTree ({0})",Key)); + else if (comp < 0) + { + if (parent.Left != null) + throw new InvalidOperationException("Another Key is already attached to Parent (left)"); + parent.Left = this; + } + else + { + if (parent.Right != null) + throw new InvalidOperationException("Another Key is already attached to Parent (right)"); + parent.Right = this; + } + Parent = parent; + } + } + public void Detach() + { + if (this.Parent != null) + { + if (this.Parent.Left == this) + this.Parent.Left = null; + else if (this.Parent.Right == this) + this.Parent.Right = null; + + Parent = null; + } + } + + public override string ToString() + { + return String.Format("[TreeNode Key={0} Value={1}]",Key,Value); + } + + } + + } +} diff --git a/btree/MappingBTree.cs b/btree/MappingBTree.cs new file mode 100644 index 0000000..bab12e0 --- /dev/null +++ b/btree/MappingBTree.cs @@ -0,0 +1,53 @@ +// /** +// * File: MappingBTree.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.Runtime.CompilerServices; +using System.Collections.Generic; +using System.Collections; + +namespace ln.types.btree +{ + public delegate K KeyMapping(V value); + + public class MappingBTree : IEnumerable + { + public KeyMapping KeyMapping { get; } + + private BTree tree = new BTree(); + + public MappingBTree(KeyMapping keyMapping) + { + KeyMapping = keyMapping; + } + + public V this[K key] + { + get => tree[key]; + set => tree[key] = value; + } + + public int Count => tree.Count; + public void Add(V v) => tree.Add(KeyMapping(v), v); + public void Remove(V v) => tree.Remove(KeyMapping(v)); + public bool TryRemove(V v) => tree.TryRemove(KeyMapping(v)); + + public bool Contains(V v) => tree.ContainsKey(KeyMapping(v)); + public bool ContainsKey(K k) => tree.ContainsKey(k); + + public IEnumerable Keys => tree.Keys; + public IEnumerable Values => tree.Values; + + public V Next(V value) => tree[tree.Next(KeyMapping(value))]; + public V Previous(V value) => tree[tree.Previous(KeyMapping(value))]; + + public IEnumerator GetEnumerator() => Values.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => Values.GetEnumerator(); + } +} diff --git a/ln.types.csproj b/ln.types.csproj index af0cf59..30f86d0 100644 --- a/ln.types.csproj +++ b/ln.types.csproj @@ -41,6 +41,9 @@ ..\packages\LiteDB.4.1.4\lib\net40\LiteDB.dll + + nunit + @@ -83,7 +86,11 @@ - + + + + + @@ -91,6 +98,8 @@ + + diff --git a/odb/ODB.cs b/odb/ODB.cs index 63e0335..261b6ff 100644 --- a/odb/ODB.cs +++ b/odb/ODB.cs @@ -23,7 +23,7 @@ namespace ln.types.odb { public String BasePath { get; set; } - Dictionary collections = new Dictionary(); + internal Dictionary collections = new Dictionary(); public ODB(string basePath) { @@ -35,7 +35,9 @@ namespace ln.types.odb public ODBCollection GetCollection(string colName) { if (!collections.ContainsKey(colName)) - collections[colName] = new ODBCollection(this, colName); + { + new ODBCollection(this, colName); + } return collections[colName]; } @@ -48,9 +50,12 @@ namespace ln.types.odb internal void DisposeCollection(ODBCollection collection) { - ODBCollection check = collections[collection.CollectionName]; - if (check == collection) - collections.Remove(collection.CollectionName); + if (collections.ContainsKey(collection.CollectionName)) + { + ODBCollection check = collections[collection.CollectionName]; + if (check == collection) + collections.Remove(collection.CollectionName); + } } private void Initialize() @@ -61,6 +66,7 @@ namespace ln.types.odb { foreach (ODBCollection col in collections.Values.ToArray()) { + col.Close(); col.Dispose(); } } diff --git a/odb/ODBCollection.DocumentIndex.DocumentIndexEntry.cs b/odb/ODBCollection.DocumentIndex.DocumentIndexEntry.cs index d56cc9e..9603bab 100644 --- a/odb/ODBCollection.DocumentIndex.DocumentIndexEntry.cs +++ b/odb/ODBCollection.DocumentIndex.DocumentIndexEntry.cs @@ -9,242 +9,30 @@ namespace ln.types.odb public partial class DocumentIndex { - public class DocumentIndexEntry + public class Area { - 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 int Size { get; private set; } - public long NextOffset => Offset + BufferLength + 4; + public long NextOffset => Offset + Size + 4; - private ODBValue documentID; - public ODBValue DocumentID + public ODBValue DocumentID { get; set; } + + public Area(long offset,int size) { - get => documentID; - set - { - lock (Index) - { - if (!ODBNull.Instance.Equals(documentID)) - { - Index.idLookup.Remove(documentID); - } - documentID = value; - if (!ODBNull.Instance.Equals(documentID)) - { - if (Index.idLookup.ContainsKey(documentID)) - { - throw new ArgumentException(String.Format("DocumentID {0} alread present",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(); - - Index.Log("NEWOFFSET {0}",this); + Size = size; + DocumentID = ODBNull.Instance; } - - private DocumentIndexEntry(DocumentIndexEntry lastEntry, int bufferLength) + public Area(long offset, int size,ODBValue documentID) + :this(offset,size) { - Last = lastEntry; - Last.Next = this; - - Index = lastEntry.Index; - Offset = lastEntry.NextOffset; - BufferLength = bufferLength; - - WriteHeader(); - Release(); - - Index.Log("FOLLOW {0}", Last); - Index.Log(" ==> {0}", this); - } - private DocumentIndexEntry(DocumentIndexEntry lastEntry,bool split = false) - { - Last = lastEntry; - Index = lastEntry.Index; - Offset = lastEntry.NextOffset; - - if (split) - { - Next = Last.Next; - Last.Next = this; - if (Next != null) - { - Next.Last = this; - BufferLength = (int)(Next.Offset - Offset - 4); - } - else - { - BufferLength = (int)(Index.StorageStream.Length - Offset - 4); - } - WriteHeader(); - Release(); - - Index.Log("INSERT {0}", Last); - Index.Log(" ==> {0}", this); - } - else - { - Last.Next = this; - Read(); - - Index.Log("NEXT {0}", this); - } - - } - - 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; - - Index.Log("UPDATE {0}", this); - } - } - - public void Release() - { - lock (Index) - { - DocumentID = ODBNull.Instance; - - Index.StorageStream.Position = Offset + 4; - Index.StorageStream.Write(new byte[BufferLength], 0, BufferLength); - - Index.Log("RELEASE {0}", this); - - 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(); - - Index.Log("IEXTEND {0}", this); - - return this; - } - return new DocumentIndexEntry(this, length); - } - throw new NotSupportedException(); - } - - private void Split(int length) - { - Index.Log("SPLIT <== {0}", this); - BufferLength = length; - Index.Log(" ==> {0}", this); - DocumentIndexEntry dieInsert = new DocumentIndexEntry(this,true); - WriteHeader(); - } - private void Combine() - { - Index.Log("COMBINE <== {0}", this); - Index.Log("COMBINE <== {0}", Next); - - BufferLength += Next.BufferLength + 4; - - Index.Log("COMBINE ==> {0}", this); - - 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; + DocumentID = documentID; } public override string ToString() { - return String.Format("[IndexEntry Offset=0x{0:x8} BufferLength=0x{1:x8} NextOffset=0x{2:X8}]",Offset,BufferLength,NextOffset); + return String.Format("[IndexEntry Offset=0x{0:x8} BufferLength=0x{1:x8} NextOffset=0x{2:X8}]",Offset,Size,NextOffset); } } diff --git a/odb/ODBCollection.DocumentIndex.cs b/odb/ODBCollection.DocumentIndex.cs index 0aadbb2..1126ee7 100644 --- a/odb/ODBCollection.DocumentIndex.cs +++ b/odb/ODBCollection.DocumentIndex.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using ln.types.odb.values; using System.IO; using ln.logging; +using ln.types.btree; +using System.Linq; namespace ln.types.odb { @@ -12,9 +14,11 @@ namespace ln.types.odb { public ODBCollection Collection { get; } public Stream StorageStream { get; } - public DocumentIndexEntry Head { get; private set; } - private Dictionary idLookup = new Dictionary(); + private Dictionary idLookup = new Dictionary(); + + private MappingBTree unusedAreas = new MappingBTree((d) => d.Offset); + private MappingBTree usedAreas = new MappingBTree((d) => d.Offset); private FileLogger transactionLogger = null; @@ -23,9 +27,57 @@ namespace ln.types.odb Collection = collection; StorageStream = stream; - EnableTranslactionLog(); + //EnableTransactionLog(); - Head = new DocumentIndexEntry(this); + Initialize(); + } + + private void Initialize() + { + long offset = 0; + + while (offset < StorageStream.Length) + { + StorageStream.Position = offset; + int asize = StorageStream.ReadInteger(); + ODBValue documentID = ODBValue.Read(StorageStream); + + Area area = new Area(offset, asize, documentID); + + Log("INIT: O:0x{0:X8} S:0x{1:X8} N:0x{2:X8} {3}", area.Offset, area.Size, area.NextOffset, area.DocumentID); + + if (ODBNull.Instance.Equals(documentID)) + unusedAreas.Add(area); + else + { + if (idLookup.ContainsKey(documentID)) + { + byte[] aBytes = Load(idLookup[documentID]); + ODBDocument aDoc = new ODBDocument(aBytes, 0, aBytes.Length); + byte[] bBytes = Load(area); + ODBDocument bDoc = new ODBDocument(bBytes, 0, bBytes.Length); + + if (aDoc.StorageTimeStamp < bDoc.StorageTimeStamp) + { + WriteArea(idLookup[documentID], ODBNull.Instance, new byte[0]); + + usedAreas.Add(area); + idLookup.Add(documentID, area); + } + else + { + WriteArea(area, ODBNull.Instance, new byte[0]); + } + } + else + { + usedAreas.Add(area); + idLookup.Add(documentID, area); + } + } + + offset = area.NextOffset; + } } public void Close() @@ -37,7 +89,7 @@ namespace ln.types.odb } } - public void EnableTranslactionLog() + public void EnableTransactionLog() { if (transactionLogger == null) { @@ -57,39 +109,106 @@ namespace ln.types.odb transactionLogger.Message(LogLevel.INFO, transaction); } - - - public IEnumerable IndexEntries + public bool Contains(ODBValue documentID) { - get + return idLookup.ContainsKey(documentID); + } + + public byte[] Load(ODBValue documentID) + { + lock (this) { - DocumentIndexEntry entry = Head; - while (entry != null) + if (idLookup.ContainsKey(documentID)) { - yield return entry; - entry = entry.Next; + Area area = idLookup[documentID]; + return Load(area); } + return null; + } + } + public byte[] Load(Area area) + { + lock (this) + { + byte[] buffer = new byte[area.Size]; + StorageStream.Position = area.Offset + 4; + StorageStream.Read(buffer, 0, area.Size); + return buffer; } } - public DocumentIndexEntry Lookup(ODBValue ID) + public void Store(ODBValue documentID, byte[] storageBytes) { - foreach (DocumentIndexEntry die in IndexEntries) + lock (this) { - if (ID.Equals(die.DocumentID)) - return die; + Area previousArea = null; + Area storageArea = FindUnused(storageBytes.Length); + + if (idLookup.ContainsKey(documentID)) + previousArea = idLookup[documentID]; + + if (storageArea == null) + storageArea = new Area(StorageStream.Length, storageBytes.Length); + + WriteArea(storageArea, documentID, storageBytes); + if (previousArea != null) + WriteArea(previousArea, ODBNull.Instance, new byte[0]); } + } + public void Remove(ODBValue documentID) + { + lock (this) + { + Area area = idLookup[documentID]; + WriteArea(area, ODBNull.Instance, new byte[0]); + } + } + + private void WriteArea(Area area,ODBValue documentID,byte[] storageBytes) + { + Log("OFFSET(0x{0:X8}) SIZE(0x{1:X8}) ID: {2}",area.Offset,area.Size,documentID); + + StorageStream.Position = area.Offset; + StorageStream.WriteInteger(area.Size); + StorageStream.Write(storageBytes, 0, storageBytes.Length); + if (storageBytes.Length < area.Size) + { + byte[] zero = new byte[area.Size - storageBytes.Length]; + StorageStream.Write(zero, 0, zero.Length); + } + + if ((ODBNull.Instance.Equals(documentID)) && (!ODBNull.Instance.Equals(area.DocumentID))) + { + usedAreas.Remove(area); + unusedAreas.Add(area); + if (idLookup[area.DocumentID] == area) + idLookup.Remove(area.DocumentID); + } + else if ((!ODBNull.Instance.Equals(documentID)) && (ODBNull.Instance.Equals(area.DocumentID))) + { + unusedAreas.TryRemove(area); + usedAreas.Add(area); + idLookup[documentID] = area; + } + area.DocumentID = documentID; + } + + + public IEnumerable UsedAreas => usedAreas.Values; + + public Area Lookup(ODBValue documentID) + { + if (idLookup.ContainsKey(documentID)) + return idLookup[documentID]; return null; } - public DocumentIndexEntry FindUnused(int minLength) + public Area FindUnused(int minLength) { - foreach (DocumentIndexEntry die in IndexEntries) + foreach (Area area in unusedAreas) { - if (die.IsUnused && (die.BufferLength > minLength)) - return die; - if (die.Next == null) - return die.Extend(minLength); + if (area.Size >= minLength) + return area; } return null; } @@ -98,11 +217,7 @@ namespace ln.types.odb { return idLookup.Keys.GetEnumerator(); } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } } diff --git a/odb/ODBCollection.cs b/odb/ODBCollection.cs index 12b72eb..9ba3d40 100644 --- a/odb/ODBCollection.cs +++ b/odb/ODBCollection.cs @@ -21,9 +21,13 @@ namespace ln.types.odb FileStream fileStream; DocumentIndex documentIndex; + Dictionary propertyIndeces = new Dictionary(); + internal ODBCollection(ODB odb,string collectionName) { ODB = odb; + odb.collections.Add(collectionName, this); + CollectionName = collectionName; Initialize(); @@ -31,7 +35,7 @@ namespace ln.types.odb private void Initialize() { - fileStream = new FileStream(Path.Combine(ODB.BasePath, String.Format("{0}.col",CollectionName)),FileMode.OpenOrCreate,FileAccess.ReadWrite); + fileStream = new FileStream(Path.Combine(ODB.BasePath, String.Format("{0}.col",CollectionName)),FileMode.OpenOrCreate,FileAccess.ReadWrite); documentIndex = new DocumentIndex(fileStream,this); } @@ -43,91 +47,144 @@ namespace ln.types.odb public bool Insert(ODBDocument document) { - DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(document.ID); - if (die == null) + if (Index.Contains(document.ID)) + return false; + + byte[] docBytes = document.ToStorage(); + Index.Store(document.ID, docBytes); + + foreach (PropertyIndex propIndex in propertyIndeces.Values) { - byte[] docBytes = document.ToStorage(); - die = documentIndex.FindUnused(docBytes.Length); - - die.Update(document.ID,docBytes); - - return true; + propIndex.Add(document[propIndex.Name], document.ID); } - return false; + + return true; } 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; + if (!Index.Contains(document.ID)) + return false; + + byte[] docBytes = document.ToStorage(); + Index.Store(document.ID, docBytes); + + return true; } 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(); + Index.Store(document.ID, docBytes); return true; } - - public ODBDocument GetDocumentByID(ODBValue id) + public void Delete(ODBValue documentID) { - Logging.Log(LogLevel.DEBUG, "ODBCollection.GetDocumentByID(): {0}",id); - DocumentIndex.DocumentIndexEntry die = documentIndex.Lookup(id); - if (die != null) + ODBDocument document = GetDocumentByID(documentID); + + foreach (PropertyIndex propIndex in propertyIndeces.Values) { - byte[] storageBytes = die.ReadStorageBytes(); - ODBDocument document = new ODBDocument(storageBytes, 0, storageBytes.Length); - return document; + propIndex.Remove(document[propIndex.Name], document.ID); } - return null; + + Index.Remove(documentID); } + public ODBDocument GetDocumentByID(ODBValue documentID) + { + //Logging.Log(LogLevel.DEBUGDETAIL, "ODBCollection.GetDocumentByID(): {0}",documentID); + byte[] storageBytes = Index.Load(documentID); + ODBDocument document = new ODBDocument(storageBytes, 0, storageBytes.Length); + return document; + } + + public IEnumerable FindIDs(string propertyName, ODBValue value) + { + if (propertyIndeces.ContainsKey(propertyName)) + { + foreach (ODBValue documentID in propertyIndeces[propertyName].Find(value)) + { + if (documentID != null) + yield return documentID; + } + } + else + { + foreach (ODBDocument document in this) + { + if (value.Equals(document[propertyName])) + yield return document.ID; + } + } + } public IEnumerable Find(string propertyName, ODBValue value) { - foreach (ODBDocument document in this) + lock (this) { - if (value.Equals(document[propertyName])) - yield return document; + if (propertyIndeces.ContainsKey(propertyName)) + { + foreach (ODBValue documentID in propertyIndeces[propertyName].Find(value)) + { + if (documentID != null) + yield return GetDocumentByID(documentID); + } + } + else + { + 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) + lock (this) { - if (value.Equals(document[propertyName])) - return document; + if (propertyIndeces.ContainsKey(propertyName)) + { + foreach (ODBValue documentID in propertyIndeces[propertyName].Find(value)) + { + if (documentID != null) + return GetDocumentByID(documentID); + } + } + else + { + foreach (ODBDocument document in this) + { + if (value.Equals(document[propertyName])) + return document; + } + } } return null; } + public void EnsureIndex(string propertyName,string indexName = null) + { + if (indexName == null) + indexName = propertyName; + + lock (this) + { + if (!propertyIndeces.ContainsKey(indexName)) + { + PropertyIndex propertyIndex = new PropertyIndex(indexName); + propertyIndeces.Add(indexName, propertyIndex); + + foreach (ODBDocument doc in this) + { + propertyIndex.Add(doc[propertyName], doc.ID); + } + } + } + } + + + public IEnumerator GetEnumerator() { foreach (ODBValue id in documentIndex.ToArray()) diff --git a/odb/ODBCollection<>.cs b/odb/ODBCollection<>.cs index e653661..5ff3483 100644 --- a/odb/ODBCollection<>.cs +++ b/odb/ODBCollection<>.cs @@ -3,6 +3,9 @@ using System.Collections; using System.Collections.Generic; using ln.types.odb.values; using System.Linq; +using System.Reflection; +using System.Diagnostics; +using ln.types.threads; namespace ln.types.odb { public class ODBCollection : IEnumerable where T:class @@ -20,6 +23,11 @@ namespace ln.types.odb collection = new ODBCollection(odb, ElementType.FullName); } + public void Close() + { + collection.Close(); + } + public T this[ODBValue documentID] { get => Select(documentID); @@ -60,16 +68,25 @@ namespace ln.types.odb } public IEnumerable Select(string fieldName, object value) { - foreach (ODBDocument document in collection.Find(fieldName, ODBMapper.Default.MapValue(value))) + IEnumerable documentIDs = collection.FindIDs(fieldName, ODBMapper.Default.MapValue(value)).ToArray(); + + foreach (ODBValue documentID in documentIDs) { - yield return Select(document.ID); + yield return Select(documentID); } } public IEnumerable Select(Predicate predicate) { - return this.Where((x) => predicate(x)); + return this.Where((x) => predicate(x)).ToArray(); } + public IEnumerable Select(IEnumerable documentIDs) + { + lock (this) + { + return documentIDs.Select(id => Select(id)).ToArray(); + } + } public T Select(ODBValue documentID) { lock (this) @@ -111,6 +128,32 @@ namespace ln.types.odb } } + public void Delete(T o) + { + lock (this) + { + ODBDocument document = ODBMapper.Default.MapValue(o) as ODBDocument; + collection.Delete(document.ID); + } + } + + public void EnsureIndex(string name) + { + String backingFieldName = name; + PropertyInfo propertyInfo = ElementType.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + if (propertyInfo != null) + { + backingFieldName = String.Format("<{0}>k__BackingField", name); + + FieldInfo fieldInfo = ElementType.GetField(backingFieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + if (fieldInfo == null) + backingFieldName = name; + } + + collection.EnsureIndex(backingFieldName,name); + } + + public IEnumerator GetEnumerator() { ODBValue[] documentIDs = null; diff --git a/odb/ODBDocument.cs b/odb/ODBDocument.cs index 6f7cda6..80485b2 100644 --- a/odb/ODBDocument.cs +++ b/odb/ODBDocument.cs @@ -15,6 +15,7 @@ namespace ln.types.odb } public ODBValue ID { get; set; } = new ODBGuid(); + public DateTime StorageTimeStamp { get; private set; } public ODBDocument(byte[] bytes,int offset,int length) :this() @@ -22,6 +23,8 @@ namespace ln.types.odb int endOffset = offset + length; ID = ODBValue.Deserialize(bytes, ref offset); + StorageTimeStamp = ODBValue.Deserialize(bytes, ref offset).AsDateTime; + int nProps = BitConverter.ToInt32(bytes, offset); offset += 4; @@ -59,6 +62,8 @@ namespace ln.types.odb public IEnumerable Keys => properties.Keys; + public override int CompareLevel => 128; + public bool Contains(ODBStringValue propName) { return !ODBNull.Instance.Equals(this[propName]); @@ -70,6 +75,8 @@ namespace ln.types.odb BinaryWriter writer = new BinaryWriter(stream); ID.Store(writer); + ((ODBValue)DateTime.Now).Store(writer); + writer.Write(properties.Count); foreach (ODBValue propName in properties.Keys) @@ -101,6 +108,11 @@ namespace ln.types.odb return false; } + public override int CompareInType(ODBValue other) + { + return ID.CompareTo(other.AsDocument.ID); + } + static ODBDocument() { RegisterDeserializer(0x1000, (b,o,l) => new ODBDocument(b,o,l)); diff --git a/odb/PropertyIndex.cs b/odb/PropertyIndex.cs new file mode 100644 index 0000000..dec5abb --- /dev/null +++ b/odb/PropertyIndex.cs @@ -0,0 +1,63 @@ +// /** +// * File: FieldIndex.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; +using ln.types.odb.values; +using System.Collections; +using System.Collections.Generic; +namespace ln.types.odb +{ + public class PropertyIndex + { + public String Name { get; } + + BTree> bTree; + + public PropertyIndex(String name) + { + Name = name; + bTree = new BTree>(ODBValue.Compare); + } + + public IEnumerable Find(ODBValue lookup) + { + if (bTree.ContainsKey(lookup)) + { + foreach (ODBValue documentID in bTree[lookup]) + yield return documentID; + } + } + + public void Add(ODBValue value,ODBValue documentID) + { + List indList = null; + if (!bTree.ContainsKey(value)) + { + indList = new List(); + bTree[value] = indList; + } + else + { + indList = bTree[value]; + } + indList.Add(documentID); + } + public void Remove(ODBValue value,ODBValue documentID) + { + if (bTree.ContainsKey(value)) + { + bTree[value].Remove(documentID); + } + } + + + + } +} diff --git a/odb/values/ODBBool.cs b/odb/values/ODBBool.cs index 5ddcdd1..4c294f4 100644 --- a/odb/values/ODBBool.cs +++ b/odb/values/ODBBool.cs @@ -12,6 +12,8 @@ namespace ln.types.odb.values { public class ODBBool : ODBValue { + public override int CompareLevel => 254; + public ODBBool() :base(0x04) {} @@ -27,6 +29,14 @@ namespace ln.types.odb.values return new byte[] { AsBool ? (byte)0xFF : (byte)0x00 }; } + public override int CompareInType(ODBValue other) + { + if (AsBool == other.AsBool) + return 0; + if (AsBool) + return 1; + return -1; + } static ODBBool() { diff --git a/odb/values/ODBDouble.cs b/odb/values/ODBDouble.cs index a79daf0..9313c61 100644 --- a/odb/values/ODBDouble.cs +++ b/odb/values/ODBDouble.cs @@ -3,6 +3,8 @@ namespace ln.types.odb.values { public class ODBDouble : ODBValue { + public override int CompareLevel => 2; + public ODBDouble() :base(0x18) { @@ -18,6 +20,18 @@ namespace ln.types.odb.values return BitConverter.GetBytes(AsDouble); } + public override int CompareInType(ODBValue other) + { + double a = AsDouble; + double b = other.AsDouble; + + if (Math.Abs(a - b) < double.Epsilon) + return 0; + if (a < b) + return -1; + return 1; + } + static ODBDouble() { RegisterDeserializer(0x0018, (b, o, l) => BitConverter.ToDouble(b, o)); diff --git a/odb/values/ODBGuid.cs b/odb/values/ODBGuid.cs index c68e5ae..dacd3db 100644 --- a/odb/values/ODBGuid.cs +++ b/odb/values/ODBGuid.cs @@ -4,6 +4,8 @@ namespace ln.types.odb.values { public class ODBGuid : ODBValue { + public override int CompareLevel => 20; + public ODBGuid() :base(0x03) { @@ -27,6 +29,11 @@ namespace ln.types.odb.values return new Guid(s); } + public override int CompareInType(ODBValue other) + { + return AsGuid.CompareTo(other.AsGuid); + } + static ODBGuid() { RegisterDeserializer(0x03, (b,o,l) => FromByteArray(b,o)); diff --git a/odb/values/ODBInteger.cs b/odb/values/ODBInteger.cs index 9b73d69..679aea9 100644 --- a/odb/values/ODBInteger.cs +++ b/odb/values/ODBInteger.cs @@ -16,8 +16,15 @@ namespace ln.types.odb.values public override bool AsBool => AsInt != 0; + public override int CompareLevel => 0; + public override byte[] ToStorage() => BitConverter.GetBytes(AsInt); + public override int CompareInType(ODBValue other) + { + return AsInt - other.AsInt; + } + static ODBInteger() { RegisterDeserializer(0x10, (b, o, l) => BitConverter.ToInt32(b, o)); @@ -29,6 +36,8 @@ namespace ln.types.odb.values } public class ODBUInteger : ODBValue { + public override int CompareLevel => 5; + public ODBUInteger() : base(0x11) { @@ -41,6 +50,16 @@ namespace ln.types.odb.values public override byte[] ToStorage() => BitConverter.GetBytes(AsUInt); + public override int CompareInType(ODBValue other) + { + long d = AsUInt - other.AsUInt; + if (d == 0) + return 0; + if (d < 0) + return -1; + return 1; + } + static ODBUInteger() { RegisterDeserializer(0x11, (b, o, l) => BitConverter.ToUInt32(b, o)); diff --git a/odb/values/ODBList.cs b/odb/values/ODBList.cs index 22cdfa7..b50e2db 100644 --- a/odb/values/ODBList.cs +++ b/odb/values/ODBList.cs @@ -56,6 +56,8 @@ namespace ln.types.odb.values } } + public override int CompareLevel => 253; + public override byte[] ToStorage() { MemoryStream stream = new MemoryStream(); @@ -69,6 +71,12 @@ namespace ln.types.odb.values return stream.ToArray(); } + public override int CompareInType(ODBValue other) + { + // ToDO: Implement List comparison + return 0; + } + static ODBList() { RegisterDeserializer(0x02, (b, o, l) => new ODBList(b,o,l)); diff --git a/odb/values/ODBLong.cs b/odb/values/ODBLong.cs index 1761039..20195b6 100644 --- a/odb/values/ODBLong.cs +++ b/odb/values/ODBLong.cs @@ -16,9 +16,24 @@ namespace ln.types.odb.values public override byte[] ToStorage() => BitConverter.GetBytes(AsLong); + public override int CompareInType(ODBValue other) + { + long a, b; + a = AsLong; + b = other.AsLong; + + long d = a - b; + if (d == 0) + return 0; + if (d < 0) + return -1; + return 1; + } + public override DateTime AsDateTime => DateTimeOffset.FromUnixTimeMilliseconds(AsLong).DateTime; public override TimeSpan AsTimeSpan => TimeSpan.FromMilliseconds(AsDouble); + public override int CompareLevel => 1; static ODBLong() { @@ -30,6 +45,8 @@ namespace ln.types.odb.values } public class ODBULong : ODBValue { + public override int CompareLevel => 6; + public ODBULong() : base(0x13) { @@ -42,6 +59,18 @@ namespace ln.types.odb.values public override byte[] ToStorage() => BitConverter.GetBytes(AsULong); + public override int CompareInType(ODBValue other) + { + ulong a = AsULong; + ulong b = other.AsULong; + + if (a == b) + return 0; + if (a < b) + return -1; + return 1; + } + static ODBULong() { RegisterDeserializer(0x13, (b, o, l) => BitConverter.ToUInt64(b, o)); diff --git a/odb/values/ODBNull.cs b/odb/values/ODBNull.cs index 00df3c7..42eaf43 100644 --- a/odb/values/ODBNull.cs +++ b/odb/values/ODBNull.cs @@ -6,6 +6,8 @@ namespace ln.types.odb.values { public static readonly ODBNull Instance = new ODBNull(); + public override int CompareLevel => 255; + public ODBNull() : base(0x00) { } @@ -28,5 +30,10 @@ namespace ln.types.odb.values { return (obj == null) || (obj is ODBNull); } + + public override int CompareInType(ODBValue other) + { + return 0; + } } } diff --git a/odb/values/ODBStringValue.cs b/odb/values/ODBStringValue.cs index ce6ca2c..247ac91 100644 --- a/odb/values/ODBStringValue.cs +++ b/odb/values/ODBStringValue.cs @@ -1,9 +1,12 @@ using System; using System.Text; +using System.Globalization; namespace ln.types.odb.values { public class ODBStringValue : ODBValue { + public override int CompareLevel => 10; + public ODBStringValue() : base(0x01) { } @@ -19,6 +22,10 @@ namespace ln.types.odb.values return Encoding.UTF8.GetBytes(AsString); } + public override int CompareInType(ODBValue other) + { + return AsString.CompareTo(other.AsString); + } public static implicit operator ODBStringValue(String text) { diff --git a/odb/values/ODBValue.cs b/odb/values/ODBValue.cs index 416c935..0492ca6 100644 --- a/odb/values/ODBValue.cs +++ b/odb/values/ODBValue.cs @@ -48,6 +48,9 @@ namespace ln.types.odb.values Value = value; } + public abstract int CompareLevel { get; } + public abstract int CompareInType(ODBValue other); + public abstract byte[] ToStorage(); public object AsObject => Value; @@ -146,9 +149,22 @@ namespace ln.types.odb.values throw new FormatException("wrong storage type code"); } + public int CompareTo(ODBValue other) + { + if (CompareLevel != other.CompareLevel) + return CompareLevel - other.CompareLevel; + + return CompareInType(other); + } + public override string ToString() { return String.Format("[ODBValue Value={0}]", Value); } + + public static int Compare(ODBValue a,ODBValue b) + { + return a.CompareTo(b); + } } } diff --git a/test/testODB.cs b/test/testODB.cs new file mode 100644 index 0000000..20a871a --- /dev/null +++ b/test/testODB.cs @@ -0,0 +1,153 @@ +// /** +// * File: ODB.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 NUnit.Framework; +using System; +using System.IO; +using ln.types.odb; +using Newtonsoft.Json; +using System.Diagnostics; +using ln.types.threads; +using System.Threading; +using ln.logging; +namespace ln.types.test +{ + [TestFixture()] + public class testODB + { + + [Test()] + public void TestCase() + { + String odbBase = Path.Combine(Path.GetTempPath(), "odb.test"); + + Console.WriteLine("Using path {0}", odbBase); + + if (Directory.Exists(odbBase)) + Directory.Delete(odbBase, true); + + Guid docIdOne; + + using (ODB odb = new ODB(odbBase)) + { + ODBCollection colA = odb.GetCollection(); + + int[] numbers = new int[] { 0,53,2,34,37,35,23,1,456,7777,43,3535367 }; + + foreach (int n in numbers) + { + ODBTestClassA ca = new ODBTestClassA(n); + colA.Insert(ca); + } + + ODBTestClassA cdouble = colA.SelectOne("Number", 1); + + Assert.NotNull(cdouble); + Assert.AreEqual(cdouble.Number, 1); + + docIdOne = cdouble.ID; + + bool success = colA.Insert(cdouble); + Assert.IsFalse(success); + + success = colA.Update(cdouble); + Assert.IsTrue(success); + + success = colA.Upsert(cdouble); + Assert.IsTrue(success); + + colA.Close(); + } + + using (ODB odb = new ODB(odbBase)) + { + ODBCollection colA = odb.GetCollection(); + Timing.Meassure("EnsureIndex", () => colA.EnsureIndex("Number")); + + ODBTestClassA cSelect = colA.SelectOne("Number", 1); + + Assert.AreEqual(docIdOne, cSelect.ID); + + colA.Delete(cSelect); + cSelect = colA.SelectOne("Number", 1); + + Assert.IsNull(cSelect); + + cSelect = colA.SelectOne("Number", 3); + + Assert.IsNull(cSelect); + + Random random = new Random(); + + int choose = random.Next() % 10000; + int selection = 0; + int lc = choose; + + Thread t = new Thread(() => { while (true) { Thread.Sleep(1000); Logging.Log(LogLevel.INFO," ==> {0}", lc - choose); lc = choose; }; }); + t.Start(); + + for (int m = 0; m < 5; m++) + { + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + + for (int n = 0; n < 10000; n++) + { + ODBTestClassA testMass = new ODBTestClassA(random.Next()); + colA.Upsert(testMass); + + if (choose == 0) + selection = testMass.Number; + choose--; + + } + + stopwatch.Stop(); + Console.WriteLine("Inserted 10000 Items in {0}ms", stopwatch.ElapsedMilliseconds); + } + + + Stopwatch stopwatch2 = new Stopwatch(); + stopwatch2.Start(); + ODBTestClassA selA = colA.SelectOne("Number", selection); + stopwatch2.Stop(); + Console.WriteLine("Looked up item in {0}ms", stopwatch2.ElapsedMilliseconds); + + t.Interrupt(); + } + + + + + } + } + + public class ODBTestClassA + { + [DocumentID] + public readonly Guid ID = Guid.NewGuid(); + + public String PropertyString { get; set; } + public string FieldString; + + public int Number; + + private ODBTestClassA() + { } + + public ODBTestClassA(int n) + { + Number = n; + PropertyString = String.Format("Property:{0}", n); + FieldString = String.Format("Field:{0}", n); + } + + } + +} diff --git a/threads/Timing.cs b/threads/Timing.cs new file mode 100644 index 0000000..ef8a972 --- /dev/null +++ b/threads/Timing.cs @@ -0,0 +1,47 @@ +// /** +// * File: Timing.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.Diagnostics; +using ln.logging; +namespace ln.types.threads +{ + public static class Timing + { + public delegate void VoidDelegate(); + public delegate T TypedDelegate(); + + public static void Meassure(VoidDelegate f) => Meassure("", f); + public static void Meassure(String prefix,VoidDelegate f) + { + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + f(); + stopwatch.Stop(); + Logging.Log(LogLevel.DEBUG, "Timing({1}): {0}ms", stopwatch.ElapsedMilliseconds,prefix); + } + public static T Meassure(TypedDelegate f) + { + return Meassure("", f); + } + public static T Meassure(String prefix,TypedDelegate f) + { + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + T r = f(); + stopwatch.Stop(); + Logging.Log(LogLevel.DEBUG, "Timing({1}): {0}ms", stopwatch.ElapsedMilliseconds,prefix); + + return r; + } + + + + } +}