示例#1
0
        /// <summary>
        /// Insert data inside a datapage. Returns dataPageID that indicates the first page
        /// </summary>
        public DataBlock Insert(CollectionPage col, byte[] data)
        {
            // need to extend (data is bigger than 1 page)
            var extend = (data.Length + DataBlock.DATA_BLOCK_FIXED_SIZE) > BasePage.PAGE_AVAILABLE_BYTES;

            // if extend, just search for a page with BLOCK_SIZE available
            var dataPage = _pager.GetFreePage <DataPage>(col.FreeDataPageID, extend ? DataBlock.DATA_BLOCK_FIXED_SIZE : 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
            };

            // if extend, store all bytes on extended page.
            if (extend)
            {
                var extendPage = _pager.NewPage <ExtendPage>();
                block.ExtendPageID = extendPage.PageID;
                this.StoreExtendData(extendPage, data);
            }
            else
            {
                block.Data = data;
            }

            // add dataBlock to this page
            dataPage.DataBlocks.Add(block.Position.Index, block);

            // update freebytes + items count
            dataPage.UpdateItemCount();

            // set page as dirty
            _pager.SetDirty(dataPage);

            // add/remove dataPage on freelist if has space
            _pager.AddOrRemoveToFreeList(dataPage.FreeBytes > DataPage.DATA_RESERVED_BYTES, dataPage, col, ref col.FreeDataPageID);

            // increase document count in collection
            col.DocumentCount++;

            // set collection page as dirty
            _pager.SetDirty(col);

            return(block);
        }
示例#2
0
        /// <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.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 > BasePage.RESERVED_BYTES, dataPage, col, ref col.FreeDataPageID);

            col.DocumentCount++;

            col.IsDirty = true;

            return(block);
        }
示例#3
0
        /// <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);
        }
示例#4
0
        /// <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);
        }
示例#5
0
        /// <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);
        }