using System; using System.Collections.Generic; using System.Threading; namespace ln.bson.storage.index { public class IndexTree { private IndexLeaf _root = new IndexLeaf(); public void Query(string path, QueryOperator queryOperator, byte[] value, ISet resultSet) => Query(path.Split('.'), queryOperator, value, resultSet); public void Query(Span path, QueryOperator queryOperator, byte[] value, ISet resultSet) { if (!_root.TryGetLeaf(path, out IndexLeaf indexLeaf)) throw new KeyNotFoundException(); indexLeaf.Index.Query(queryOperator, value, resultSet); } public void AddDocument(long key, BsonDocument bsonDocument) => _root.AddValue(key, bsonDocument); public void RemoveDocument(long key) => _root.RemoveValue(key); public void ReplaceDocument(long oldKey, long newKey, BsonDocument newDocument) => _root.ReplaceValue(oldKey, newKey, newDocument); public bool EnsureIndex(string path, Comparison comparison) => EnsureIndex(path, comparison, out IBsonIndex bsonIndex); public bool EnsureIndex(string path, Comparison comparison, out IBsonIndex bsonIndex) { _root.EnsureLeaf(path.Split('.',StringSplitOptions.None), out IndexLeaf indexLeaf); return indexLeaf.EnsureIndex(comparison, out bsonIndex); } public void Clear() => _root.Clear(); class IndexLeaf { private Dictionary _children = new Dictionary(); private IBsonIndex _index; public IBsonIndex Index => _index; public void EnsureLeaf(Span path, out IndexLeaf indexLeaf) { if (path.IsEmpty) indexLeaf = this; else { if (!_children.TryGetValue(path[0], out IndexLeaf childLeaf)) { childLeaf = new IndexLeaf(); _children.Add(path[0], childLeaf); } childLeaf.EnsureLeaf(path.Slice(1), out indexLeaf); } } public bool TryGetLeaf(Span path, out IndexLeaf indexLeaf) { if (path.IsEmpty) { indexLeaf = this; return true; } else { if (!_children.TryGetValue(path[0], out IndexLeaf childLeaf)) { indexLeaf = null; return false; } return childLeaf.TryGetLeaf(path.Slice(1), out indexLeaf); } } public bool EnsureIndex() => EnsureIndex(BsonIndex.CompareBytesLittleEndian, out IBsonIndex bsonIndex); public bool EnsureIndex(Comparison comparison, out IBsonIndex bsonIndex) { if (_index is null) { bsonIndex = _index = new BsonIndex(comparison); return true; } bsonIndex = _index; return false; } public void AddValue(long key, BsonValue bsonValue) { if (_index is not null) _index.AddValue(key, bsonValue); if (bsonValue is BsonDocument bsonDocument) { foreach (KeyValuePair child in _children) { if (bsonDocument.Contains(child.Key)) child.Value.AddValue(key, bsonDocument[child.Key]); } } } public void RemoveValue(long key) { if (_index is not null) _index.RemoveValue(key); foreach (KeyValuePair child in _children) child.Value.RemoveValue(key); } public void ReplaceValue(long oldKey, long newKey, BsonValue newValue) { if (_index is not null) _index.ReplaceValue(oldKey, newKey, newValue); if (newValue is BsonDocument newDocument) { foreach (KeyValuePair child in _children) { if (newDocument.Contains(child.Key)) child.Value.ReplaceValue(oldKey, newKey, newDocument[child.Key]); else child.Value.RemoveValue(oldKey); } } else { foreach (KeyValuePair child in _children) child.Value.RemoveValue(oldKey); } } public void Clear() { if (_index is not null) _index.Clear(); foreach (KeyValuePair child in _children) child.Value.Clear(); } } } }