Exemple #1
0
        /// <summary>
        /// Add/Remove page into free slots on collection page. Used when some data are removed/changed
        /// For insert data, this method are called from GetFreePage
        /// </summary>
        public void AddOrRemoveFreeList <T>(T page, int initialSlot) where T : BasePage
        {
            ENSURE(page.PageType == PageType.Index || page.PageType == PageType.Data, "only index/data page contains free linked-list");

            var newSlot = BasePage.FreeIndexSlot(page.FreeBytes);

            // there is no slot change - just exit (no need any change) [except if has no more items)
            if (newSlot == initialSlot && page.ItemsCount > 0)
            {
                return;
            }

            // select if I will get from free index list or data list
            var freeLists = page.PageType == PageType.Index ?
                            _collectionPage.FreeIndexPageID :
                            _collectionPage.FreeDataPageID;

            // remove from intial slot
            this.RemoveFreeList <T>(page, ref freeLists[initialSlot]);

            // if there is no items, delete page
            if (page.ItemsCount == 0)
            {
                this.DeletePage(page);
            }
            else
            {
                // add into current slot
                this.AddFreeList <T>(page, ref freeLists[newSlot]);
            }
        }
Exemple #2
0
        /// <summary>
        /// Delete a single index node - fix tree double-linked list levels
        /// </summary>
        private void DeleteSingleNode(IndexNode node)
        {
            for (int i = node.Level - 1; i >= 0; i--)
            {
                // get previous and next nodes (between my deleted node)
                var prevNode = this.GetNode(node.Prev[i]);
                var nextNode = this.GetNode(node.Next[i]);

                if (prevNode != null)
                {
                    prevNode.SetNext((byte)i, node.Next[i]);
                }
                if (nextNode != null)
                {
                    nextNode.SetPrev((byte)i, node.Prev[i]);
                }
            }

            // get current slot position in free list
            var slot = BasePage.FreeIndexSlot(node.Page.FreeBytes);

            node.Page.DeleteIndexNode(node.Position.Index);

            // update (if needed) slot position
            _snapshot.AddOrRemoveFreeList(node.Page, slot);
        }
Exemple #3
0
        /// <summary>
        /// Returns a page that contains space enough to data to insert new object - if one does not exit, creates a new page.
        /// Before return page, fix empty free list slot according with passed length
        /// </summary>
        public T GetFreePage <T>(int bytesLength)
            where T : BasePage
        {
            var length = bytesLength + BasePage.SLOT_SIZE; // add +4 bytes for footer slot

            // select if I will get from free index list or data list
            var freeLists = typeof(T) == typeof(IndexPage) ?
                            _collectionPage.FreeIndexPageID :
                            _collectionPage.FreeDataPageID;

            // get minimum slot to check for free page. Returns -1 if need NewPage
            var startSlot = BasePage.GetMinimumIndexSlot(length);

            // check for avaiable re-usable page
            for (int currentSlot = startSlot; currentSlot >= 0; currentSlot--)
            {
                var freePageID = freeLists[currentSlot];

                // there is no free page here, try find princess in another castle
                if (freePageID == uint.MaxValue)
                {
                    continue;
                }

                var page = this.GetPage <T>(freePageID);

                var newSlot = BasePage.FreeIndexSlot(page.FreeBytes - length);

                // if slots will change, fix now
                if (currentSlot != newSlot)
                {
                    this.RemoveFreeList <T>(page, ref freeLists[currentSlot]);
                    this.AddFreeList <T>(page, ref freeLists[newSlot]);
                }

                ENSURE(page.FreeBytes >= length, "ensure selected page has space enougth for this content");

                // mark page page as dirty
                page.IsDirty = true;

                return(page);
            }

            // if not page avaiable, create new and add in free list
            var newPage = this.NewPage <T>();

            // get slot based on how many blocks page will have after use
            var slot = BasePage.FreeIndexSlot(newPage.FreeBytes - length - BasePage.SLOT_SIZE);

            // and add into free-list
            this.AddFreeList <T>(newPage, ref freeLists[slot]);

            return(newPage);
        }
Exemple #4
0
        /// <summary>
        /// Delete all datablock that contains a document (can use multiples data blocks)
        /// </summary>
        public void Delete(PageAddress blockAddress)
        {
            // delete all document blocks
            while (blockAddress != PageAddress.Empty)
            {
                var page  = _snapshot.GetPage <DataPage>(blockAddress.PageID);
                var block = page.GetBlock(blockAddress.Index);
                var slot  = BasePage.FreeIndexSlot(page.FreeBytes);

                // delete block inside page
                page.DeleteBlock(blockAddress.Index);

                // fix page empty list (or delete page)
                _snapshot.AddOrRemoveFreeList(page, slot);

                blockAddress = block.NextBlock;
            }
        }
Exemple #5
0
        /// <summary>
        /// Update document using same page position as reference
        /// </summary>
        public void Update(CollectionPage col, PageAddress blockAddress, BsonDocument doc)
        {
            var bytesLeft = doc.GetBytesCount(true);

            if (bytesLeft > MAX_DOCUMENT_SIZE)
            {
                throw new LiteException(0, "Document size exceed {0} limit", MAX_DOCUMENT_SIZE);
            }

            DataBlock lastBlock     = null;
            var       updateAddress = blockAddress;

            IEnumerable <BufferSlice> source()
            {
                var bytesToCopy = 0;

                while (bytesLeft > 0)
                {
                    // if last block contains new block sequence, continue updating
                    if (updateAddress.IsEmpty == false)
                    {
                        var dataPage     = _snapshot.GetPage <DataPage>(updateAddress.PageID);
                        var currentBlock = dataPage.GetBlock(updateAddress.Index);

                        // try get full page size content
                        bytesToCopy = Math.Min(bytesLeft, dataPage.FreeBytes + currentBlock.Buffer.Count);

                        // get current free slot linked list
                        var slot = BasePage.FreeIndexSlot(dataPage.FreeBytes);

                        var updateBlock = dataPage.UpdateBlock(currentBlock, bytesToCopy);

                        _snapshot.AddOrRemoveFreeList(dataPage, slot);

                        yield return(updateBlock.Buffer);

                        lastBlock = updateBlock;

                        // go to next address (if extits)
                        updateAddress = updateBlock.NextBlock;
                    }
                    else
                    {
                        bytesToCopy = Math.Min(bytesLeft, MAX_DATA_BYTES_PER_PAGE);
                        var dataPage    = _snapshot.GetFreePage <DataPage>(bytesToCopy + DataBlock.DATA_BLOCK_FIXED_SIZE);
                        var insertBlock = dataPage.InsertBlock(bytesToCopy, true);

                        if (lastBlock != null)
                        {
                            lastBlock.SetNextBlock(insertBlock.Position);
                        }

                        yield return(insertBlock.Buffer);

                        lastBlock = insertBlock;
                    }

                    bytesLeft -= bytesToCopy;
                }

                // old document was bigger than current, must delete extend blocks
                if (lastBlock.NextBlock.IsEmpty == false)
                {
                    this.Delete(lastBlock.NextBlock);
                }
            }

            // consume all source bytes to write BsonDocument direct into PageBuffer
            // must be fastest as possible
            using (var w = new BufferWriter(source()))
            {
                // already bytes count calculate at method start
                w.WriteDocument(doc, false);
                w.Consume();
            }
        }