Beispiel #1
0
        /// <summary>
        /// Async constructor
        /// </summary>
        public static async Task <BufferWriterAsync> CreateAsync(IAsyncEnumerable <BufferSlice> source)
        {
            var writer = new BufferWriterAsync(source);
            await writer.InitializeAsync();

            return(writer);
        }
Beispiel #2
0
        /// <summary>
        /// Insert BsonDocument into new data pages
        /// </summary>
        public async Task <PageAddress> Insert(BsonDocument doc)
        {
            var bytesLeft = doc.GetBytesCount(true);

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

            var firstBlock = PageAddress.Empty;

            async IAsyncEnumerable <BufferSlice> source()
            {
                var       blockIndex = 0;
                DataBlock lastBlock  = null;

                while (bytesLeft > 0)
                {
                    var bytesToCopy = Math.Min(bytesLeft, MAX_DATA_BYTES_PER_PAGE);
                    var dataPage    = await _snapshot.GetFreeDataPage(bytesToCopy + DataBlock.DATA_BLOCK_FIXED_SIZE);

                    var dataBlock = dataPage.InsertBlock(bytesToCopy, blockIndex++ > 0);

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

                    if (firstBlock.IsEmpty)
                    {
                        firstBlock = dataBlock.Position;
                    }

                    await _snapshot.AddOrRemoveFreeDataList(dataPage);

                    yield return(dataBlock.Buffer);

                    lastBlock = dataBlock;

                    bytesLeft -= bytesToCopy;
                }
            }

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

                await writer.Consume();
            }

            return(firstBlock);
        }
Beispiel #3
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();
            }
        }