public static int GetKeyLength(BsonValue key) { return(1 + // DataType key.GetBytesCount(false) + // BsonValue (key.IsString || key.IsBinary ? 1 : 0)); // Key Length }
/// <summary> /// Get how many bytes will be used to store this value. Must consider: /// [1 byte] - BsonType /// [1 byte] - KeyLength (used only in String|Byte[]) /// [N bytes] - BsonValue in bytes (0-254) /// </summary> public static int GetKeyLength(BsonValue key) { return 1 + ((key.IsString || key.IsBinary) ? 1 : 0) + key.GetBytesCount(true); }
/// <summary> /// Insert a new node index inside an collection index. /// </summary> private IndexNode AddNode(CollectionIndex index, BsonValue key, byte level) { // creating a new index node var node = new IndexNode(level) { Key = key, KeyLength = key.GetBytesCount() }; if (node.KeyLength > MAX_INDEX_LENGTH) { throw LiteException.IndexKeyTooLong(); } // 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); // update freebytes + items count page.UpdateItemCount(); // now, let's link my index node on right place var cur = this.GetNode(index.HeadNode); // scan from top left for (var 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.Options.Unique) throw LiteException.IndexDuplicateKey(index.Field, key); 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.INDEX_RESERVED_BYTES, page, index.Page, ref index.FreeIndexPageID); page.IsDirty = true; return node; }
/// <summary> /// Insert a new node index inside an collection index. /// </summary> private IndexNode AddNode(CollectionIndex index, BsonValue key, byte level, IndexNode last) { // calc key size var keyLength = key.GetBytesCount(false); if (keyLength > MAX_INDEX_LENGTH) { throw LiteException.IndexKeyTooLong(); } // creating a new index node var node = new IndexNode(level) { Key = key, KeyLength = (ushort)keyLength, Slot = (byte)index.Slot }; // 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); // update freebytes + items count page.UpdateItemCount(); // now, let's link my index node on right place var cur = this.GetNode(index.HeadNode); // using as cache last IndexNode cache = null; // scan from top left for (var i = IndexNode.MAX_LEVEL_LENGTH - 1; i >= 0; i--) { // get cache for last node cache = cache != null && cache.Position.Equals(cur.Next[i]) ? cache : this.GetNode(cur.Next[i]); // for(; <while_not_this>; <do_this>) { ... } for (; cur.Next[i].IsEmpty == false; cur = cache) { // get cache for last node cache = cache != null && cache.Position.Equals(cur.Next[i]) ? cache : this.GetNode(cur.Next[i]); // read next node to compare var diff = cache.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 LiteException.IndexDuplicateKey(index.Field, key); 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) _pager.SetDirty(cur.Page); 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; _pager.SetDirty(next.Page); } } } // add/remove indexPage on freelist if has space _pager.AddOrRemoveToFreeList(page.FreeBytes > IndexPage.INDEX_RESERVED_BYTES, page, index.Page, ref index.FreeIndexPageID); // if last node exists, create a double link list if (last != null) { // link new node with last node if (last.NextNode.IsEmpty == false) { // fix link pointer with has more nodes in list var next = this.GetNode(last.NextNode); next.PrevNode = node.Position; last.NextNode = node.Position; node.PrevNode = last.Position; node.NextNode = next.Position; _pager.SetDirty(next.Page); } else { last.NextNode = node.Position; node.PrevNode = last.Position; } // set last node page as dirty _pager.SetDirty(last.Page); } return node; }
/// <summary> /// Get how many bytes will be used to store this value. Must consider: /// [1 byte] - BsonType /// [1 byte] - KeyLength (used only in String|Byte[]) /// [N bytes] - BsonValue in bytes (0-254) /// </summary> public static int GetKeyLength(BsonValue key, bool recalc) { return(1 + ((key.IsString || key.IsBinary) ? 1 : 0) + key.GetBytesCount(recalc)); }