Ejemplo n.º 1
0
        /// <summary>
        /// Main method - serialize document. Uses ByteWriter
        /// </summary>
        public byte[] Serialize(BsonDocument doc)
        {
            var count  = doc.GetBytesCount(true);
            var writer = new ByteWriter(count);

            this.WriteDocument(writer, doc);

            return(writer.Buffer);
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Get how many bytes are available in collection to store new collections
 /// </summary>
 public int GetAvailableCollectionSpace()
 {
     return(COLLECTIONS_SIZE -
            _collections.GetBytesCount(true) -
            1 - // for int32 type (0x10)
            1 - // for new CString ('\0')
            4 - // for PageID (int32)
            8); // reserved
 }
Ejemplo n.º 3
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);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Write a bson document
        /// </summary>
        public void WriteDocument(ByteWriter writer, BsonDocument doc)
        {
            writer.Write(doc.GetBytesCount(false));

            foreach (var key in doc.Keys)
            {
                this.WriteElement(writer, key, doc[key] ?? BsonValue.Null);
            }

            writer.Write((byte)0x00);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Write BsonDocument as BSON specs. Returns document bytes count
        /// </summary>
        public int WriteDocument(BsonDocument value, bool recalc)
        {
            var bytesCount = value.GetBytesCount(recalc);

            this.Write(bytesCount);

            foreach (var el in value.GetElements())
            {
                this.WriteElement(el.Key, el.Value);
            }

            this.Write((byte)0x00);

            return(bytesCount);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Write BsonDocument as BSON specs. Returns document bytes count
        /// </summary>
        public async Task <int> WriteDocument(BsonDocument value, bool recalc)
        {
            var bytesCount = value.GetBytesCount(recalc);

            await this.Write(bytesCount);

            foreach (var el in value.GetElements())
            {
                await this.WriteElement(el.Key, el.Value);
            }

            await this.Write((byte)0x00);

            return(bytesCount);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Insert BsonDocument into new data pages
        /// </summary>
        public 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;

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

                while (bytesLeft > 0)
                {
                    var bytesToCopy = Math.Min(bytesLeft, MAX_DATA_BYTES_PER_PAGE);
                    var dataPage = _snapshot.GetFreePage<DataPage>(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;

                    yield return dataBlock.Buffer;

                    lastBlock = dataBlock;

                    bytesLeft -= bytesToCopy;
                }
            }

            // 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();
            }

            return firstBlock;
        }
Ejemplo n.º 8
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();
            }
        }
Ejemplo n.º 9
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();
            }
        }