/// <summary> /// Find all indexNodes that are greater/equals than value /// </summary> public IEnumerable <IndexNode> FindGreaterThan(CollectionIndex index, object value, bool includeValue = false) { // find first indexNode var node = this.FindOne(index, value, true); if (node == null) { yield break; } var key = new IndexKey(value); // move until next is last while (node != null) { var diff = node.Key.CompareTo(key); if (diff == 1 || (includeValue && diff == 0)) { yield return(node); } node = this.GetNode(node.Next[0]); } }
/// <summary> /// Find all nodes less than value (can be inclusive) /// </summary> public IEnumerable <IndexNode> FindLessThan(CollectionIndex index, object value, bool includeValue = false) { var key = new IndexKey(value); foreach (var node in this.FindAll(index)) { var diff = node.Key.CompareTo(key); if (diff == 1 || (!includeValue && diff == 0)) { break; } yield return(node); } }
/// <summary> /// Find nodes between start and end and (inclusive) /// </summary> public IEnumerable <IndexNode> FindBetween(CollectionIndex index, object start, object end) { // find first indexNode var node = this.FindOne(index, start, true); var key = new IndexKey(end); // navigate using next[0] do next node - if less or equals returns while (node != null) { var diff = node.Key.CompareTo(key); if (diff <= 0) { yield return(node); } node = this.GetNode(node.Next[0]); } }
/// <summary> /// Find first indexNode that match with value - if not found, can return first greater (used for greaterThan/Between) /// </summary> public IndexNode FindOne(CollectionIndex index, object value, bool greater = false) { var cur = this.GetNode(index.HeadNode); var key = new IndexKey(value); for (int i = IndexNode.MAX_LEVEL_LENGTH - 1; i >= 0; i--) { for (; cur.Next[i].IsEmpty == false; cur = this.GetNode(cur.Next[i])) { var next = this.GetNode(cur.Next[i]); var diff = next.Key.CompareTo(key); if (diff == 1 && (i > 0 || !greater)) { break; } if (diff == 1 && i == 0 && greater) { return(next); } // if equals, test for duplicates if (diff == 0) { var last = next; while (next.Key.CompareTo(key) == 0) { last = next; if (index.HeadNode.Equals(next.Prev[0])) { break; } next = this.GetNode(next.Prev[0]); } return(last); } } } return(null); }
/// <summary> /// Find all indexNodes that match with value /// </summary> public IEnumerable <IndexNode> FindEquals(CollectionIndex index, object value) { // find first indexNode var node = this.FindOne(index, value); if (node == null) { yield break; } yield return(node); var key = new IndexKey(value); // navigate using next[0] do next node - if equals, returns while (!node.Next[0].IsEmpty && ((node = this.GetNode(node.Next[0])).Key.CompareTo(key) == 0)) { yield return(node); } }
/// <summary> /// Insert data inside a datapage. Returns dataPageID that idicates the first page /// </summary> public DataBlock Insert(CollectionPage col, IndexKey key, byte[] data) { // need to extend (data is bigger than 1 page) var extend = (data.Length + key.Length + DataBlock.DATA_BLOCK_FIXED_SIZE) > BasePage.PAGE_AVAILABLE_BYTES; // if extend, just search for a page with BLOCK_SIZE avaiable var dataPage = _pager.GetFreePage <DataPage>(col.FreeDataPageID, extend ? DataBlock.DATA_BLOCK_FIXED_SIZE : key.Length + data.Length + DataBlock.DATA_BLOCK_FIXED_SIZE); // create a new block with first empty index on DataPage var block = new DataBlock { Position = new PageAddress(dataPage.PageID, dataPage.DataBlocks.NextIndex()), Page = dataPage, Key = key }; // if extend, store all bytes on extended page. if (extend) { var extendPage = _pager.NewPage <ExtendPage>(); block.ExtendData = data; block.ExtendPageID = extendPage.PageID; this.StoreExtendData(extendPage, data); } else { block.Data = data; } // add dataBlock to this page dataPage.DataBlocks.Add(block.Position.Index, block); dataPage.IsDirty = true; // add/remove dataPage on freelist if has space _pager.AddOrRemoveToFreeList(dataPage.FreeBytes > DataPage.RESERVED_BYTES, dataPage, col, ref col.FreeDataPageID); col.DocumentCount++; col.IsDirty = true; return(block); }
public static T Deserialize <T>(IndexKey key, byte[] data) { if (data == null || data.Length == 0) { throw new ArgumentNullException("data"); } object doc; if (typeof(T) == typeof(BsonDocument)) { var dict = fastBinaryJSON.BJSON.Parse(data); doc = new BsonDocument((Dictionary <string, object>)dict); } else { doc = fastBinaryJSON.BJSON.ToObject <T>(data); } SetIdValue(doc, key.Value); return((T)doc); }
/// <summary> /// Insert a new node index inside a index. Use skip list /// </summary> public IndexNode AddNode(CollectionIndex index, object value) { // create persist value - used on key var key = new IndexKey(value); var level = this.FlipCoin(); // creating a new index node var node = new IndexNode(level) { Key = key }; // get a free page to insert my index node var page = _pager.GetFreePage <IndexPage>(index.FreeIndexPageID, node.Length); node.Position = new PageAddress(page.PageID, page.Nodes.NextIndex()); node.Page = page; // add index node to page page.Nodes.Add(node.Position.Index, node); // now, let's link my index node on right place var cur = this.GetNode(index.HeadNode); // scan from top left for (int i = IndexNode.MAX_LEVEL_LENGTH - 1; i >= 0; i--) { // for(; <while_not_this>; <do_this>) { ... } for (; cur.Next[i].IsEmpty == false; cur = this.GetNode(cur.Next[i])) { // read next node to compare var diff = this.GetNode(cur.Next[i]).Key.CompareTo(key); // if unique and diff = 0, throw index exception (must rollback transaction - others nodes can be dirty) if (diff == 0 && index.Unique) { throw new LiteException(string.Format("Cannot insert duplicate key in unique index '{0}'. The duplicate value is '{1}'.", index.Field, value)); } if (diff == 1) { break; } } if (i <= (level - 1)) // level == length { // cur = current (imediatte before - prev) // node = new inserted node // next = next node (where cur is poiting) node.Next[i] = cur.Next[i]; node.Prev[i] = cur.Position; cur.Next[i] = node.Position; var next = this.GetNode(node.Next[i]); if (next != null) { next.Prev[i] = node.Position; next.Page.IsDirty = true; } cur.Page.IsDirty = true; } } // add/remove indexPage on freelist if has space _pager.AddOrRemoveToFreeList(page.FreeBytes > IndexPage.RESERVED_BYTES, page, index.Page, ref index.FreeIndexPageID); page.IsDirty = true; return(node); }
public static string Dump(this IndexKey value) { return(string.Format("{0}{1}{0}", value.Type == IndexDataType.String ? "'" : "", value.ToString())); }
public static void Write(this BinaryWriter writer, IndexKey obj) { writer.Write((byte)obj.Type); // int if (obj.Type == IndexDataType.Byte) { writer.Write((Byte)obj.Value); } else if (obj.Type == IndexDataType.Int16) { writer.Write((Int16)obj.Value); } else if (obj.Type == IndexDataType.UInt16) { writer.Write((UInt16)obj.Value); } else if (obj.Type == IndexDataType.Int32) { writer.Write((Int32)obj.Value); } else if (obj.Type == IndexDataType.UInt32) { writer.Write((UInt32)obj.Value); } else if (obj.Type == IndexDataType.Int64) { writer.Write((Int64)obj.Value); } else if (obj.Type == IndexDataType.UInt64) { writer.Write((UInt64)obj.Value); } // decimal else if (obj.Type == IndexDataType.Single) { writer.Write((Single)obj.Value); } else if (obj.Type == IndexDataType.Double) { writer.Write((Double)obj.Value); } else if (obj.Type == IndexDataType.Decimal) { writer.Write((Decimal)obj.Value); } // string else if (obj.Type == IndexDataType.String) { var length = (byte)Encoding.UTF8.GetByteCount((String)obj.Value); writer.Write(length); writer.Write((String)obj.Value, length); } // other else if (obj.Type == IndexDataType.Boolean) { writer.Write((Boolean)obj.Value); } else if (obj.Type == IndexDataType.DateTime) { writer.Write((DateTime)obj.Value); } else if (obj.Type == IndexDataType.Guid) { writer.Write((Guid)obj.Value); } // otherwise is null }