Exemple #1
0
        private IEnumerable <BsonDocument> GetList(uint pageID, string indexName, TransactionService transaction, Snapshot snapshot)
        {
            if (pageID == uint.MaxValue)
            {
                yield break;
            }

            var page = snapshot.GetPage <BasePage>(pageID);

            while (page != null)
            {
                _collections.TryGetValue(page.ColID, out var collection);

                yield return(new BsonDocument
                {
                    ["pageID"] = (int)page.PageID,
                    ["pageType"] = page.PageType.ToString(),
                    ["slot"] = (int)page.PageListSlot,
                    ["collection"] = collection,
                    ["index"] = indexName,
                    ["freeBytes"] = page.FreeBytes,
                    ["itemsCount"] = (int)page.ItemsCount
                });

                if (page.NextPageID == uint.MaxValue)
                {
                    break;
                }

                transaction.Safepoint();

                page = snapshot.GetPage <BasePage>(page.NextPageID);
            }
        }
Exemple #2
0
        /// <summary>
        /// Get last _id index key from collection. Returns MinValue if collection are empty
        /// </summary>
        private async Task <BsonValue> GetLastId(Snapshot snapshot)
        {
            var pk = snapshot.CollectionPage.PK;

            // get tail page and previous page
            var tailPage = await snapshot.GetPage <IndexPage>(pk.Tail.PageID);

            var node     = tailPage.GetIndexNode(pk.Tail.Index);
            var prevNode = node.Prev[0];

            if (prevNode == pk.Head)
            {
                return(BsonValue.MinValue);
            }
            else
            {
                var lastPage = prevNode.PageID == tailPage.PageID ? tailPage : await snapshot.GetPage <IndexPage>(prevNode.PageID);

                var lastNode = lastPage.GetIndexNode(prevNode.Index);

                var lastKey = lastNode.Key;

                return(lastKey);
            }
        }
Exemple #3
0
        /// <summary>
        /// Get a node inside a page using PageAddress - Returns null if address IsEmpty
        /// </summary>
        public IndexNode GetNode(PageAddress address)
        {
            if (address.PageID == uint.MaxValue)
            {
                return(null);
            }

            var indexPage = _snapshot.GetPage <IndexPage>(address.PageID);

            return(indexPage.GetIndexNode(address.Index));
        }
Exemple #4
0
        /// <summary>
        /// Get collection page instance (or create a new one)
        /// </summary>
        public void Get(string name, bool addIfNotExists, ref CollectionPage collectionPage)
        {
            // get collection pageID from header
            var pageID = _header.GetCollectionPageID(name);

            if (pageID != uint.MaxValue)
            {
                collectionPage = _snapshot.GetPage <CollectionPage>(pageID);
            }
            else if (addIfNotExists)
            {
                this.Add(name, ref collectionPage);
            }
        }
Exemple #5
0
        /// <summary>
        /// Get collection page instance (or create a new one). Returns null if not found and not created
        /// </summary>
        public async Task <CollectionPage> Get(string name, bool addIfNotExists)
        {
            // get collection pageID from header
            var pageID = _header.GetCollectionPageID(name);

            if (pageID != uint.MaxValue)
            {
                return(await _snapshot.GetPage <CollectionPage>(pageID));
            }
            else if (addIfNotExists)
            {
                return(await this.Add(name));
            }

            return(null);
        }
Exemple #6
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();
            }
        }
Exemple #7
0
        /// <summary>
        /// Update document using same page position as reference
        /// </summary>
        public async Task 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;

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

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

                        var currentBlock = dataPage.GetBlock(updateAddress.Index);

                        // try get full page size content (do not add DATA_BLOCK_FIXED_SIZE because will be added in UpdateBlock)
                        bytesToCopy = Math.Min(bytesLeft, dataPage.FreeBytes + currentBlock.Buffer.Count);

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

                        await _snapshot.AddOrRemoveFreeDataList(dataPage);

                        yield return(updateBlock.Buffer);

                        lastBlock = updateBlock;

                        // go to next address (if exists)
                        updateAddress = updateBlock.NextBlock;
                    }
                    else
                    {
                        bytesToCopy = Math.Min(bytesLeft, MAX_DATA_BYTES_PER_PAGE);
                        var dataPage = await _snapshot.GetFreeDataPage(bytesToCopy + DataBlock.DATA_BLOCK_FIXED_SIZE);

                        var insertBlock = dataPage.InsertBlock(bytesToCopy, true);

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

                        await _snapshot.AddOrRemoveFreeDataList(dataPage);

                        yield return(insertBlock.Buffer);

                        lastBlock = insertBlock;
                    }

                    bytesLeft -= bytesToCopy;
                }

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

                    lastBlock.SetNextBlock(PageAddress.Empty);

                    await this.Delete(nextBlockAddress);
                }
            }

            // consume all source bytes to write BsonDocument direct into PageBuffer
            await using (var writer = await BufferWriterAsync.CreateAsync(source()))
            {
                // already bytes count calculate at method start
                await writer.WriteDocument(doc, false);

                await writer.Consume();
            }
        }