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