/// <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.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; } _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 using (var w = new BufferWriter(source())) { // already bytes count calculate at method start w.WriteDocument(doc, false); w.Consume(); } return(firstBlock); }
public override PageBuffer UpdateBuffer() { _buffer.Write(this.FreeEmptyPageID, P_FREE_EMPTY_PAGE_ID); _buffer.Write(this.LastPageID, P_LAST_PAGE_ID); // update collection only if needed if (_isCollectionsChanged) { var area = _buffer.Slice(P_COLLECTIONS, COLLECTIONS_SIZE); using (var w = new BufferWriter(area)) { w.WriteDocument(_collections, true); } _isCollectionsChanged = false; } return(base.UpdateBuffer()); }
/// <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(); } }