From bad89aa9541faec45e58352281833d116b5ef4f8 Mon Sep 17 00:00:00 2001 From: dear-gary Date: Tue, 15 Apr 2025 17:02:32 +0800 Subject: [PATCH 1/2] Reduce memory allocations in BsonStreamAdapter.WriteDouble and WriteInt64 --- src/MongoDB.Bson/IO/BsonStreamAdapter.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/MongoDB.Bson/IO/BsonStreamAdapter.cs b/src/MongoDB.Bson/IO/BsonStreamAdapter.cs index 554d61c8182..26acf64939a 100644 --- a/src/MongoDB.Bson/IO/BsonStreamAdapter.cs +++ b/src/MongoDB.Bson/IO/BsonStreamAdapter.cs @@ -495,9 +495,8 @@ public override void WriteDecimal128(Decimal128 value) public override void WriteDouble(double value) { ThrowIfDisposed(); - var bytes = new byte[8]; - BinaryPrimitivesCompat.WriteDoubleLittleEndian(bytes, value); - _stream.Write(bytes, 0, 8); + BinaryPrimitivesCompat.WriteDoubleLittleEndian(_temp, value); + _stream.Write(_temp, 0, 8); } /// @@ -515,9 +514,8 @@ public override void WriteInt32(int value) public override void WriteInt64(long value) { ThrowIfDisposed(); - var bytes = new byte[8]; - BinaryPrimitives.WriteInt64LittleEndian(bytes, value); - _stream.Write(bytes, 0, 8); + BinaryPrimitives.WriteInt64LittleEndian(_temp, value); + _stream.Write(_temp, 0, 8); } /// From 34adaeae6d85a8b2c41e9b3c8fb14e942810994f Mon Sep 17 00:00:00 2001 From: dear-gary Date: Wed, 16 Apr 2025 17:26:32 +0800 Subject: [PATCH 2/2] Optimize the conversion from an array index to UTF-8 byte arrays while avoiding allocations of string objects and byte[] --- src/MongoDB.Bson/IO/BsonBinaryWriter.cs | 6 ++++-- src/MongoDB.Bson/IO/BsonStream.cs | 6 ++++++ src/MongoDB.Bson/IO/BsonStreamAdapter.cs | 9 +++++++++ src/MongoDB.Bson/IO/ByteBufferStream.cs | 17 ++++++++++++++++- .../IO/NullBsonStream.cs | 5 +++++ 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/MongoDB.Bson/IO/BsonBinaryWriter.cs b/src/MongoDB.Bson/IO/BsonBinaryWriter.cs index 42430ef4eb4..e56f5c9e983 100644 --- a/src/MongoDB.Bson/IO/BsonBinaryWriter.cs +++ b/src/MongoDB.Bson/IO/BsonBinaryWriter.cs @@ -14,6 +14,7 @@ */ using System; +using System.Buffers.Text; using System.Collections.Generic; using System.IO; @@ -29,6 +30,7 @@ public class BsonBinaryWriter : BsonWriter private readonly Stream _baseStream; #pragma warning restore CA2213 // Disposable never disposed private readonly BsonStream _bsonStream; + private readonly byte[] _temp10Bytes = new byte[10]; private BsonBinaryWriterContext _context; // constructors @@ -719,8 +721,8 @@ private void WriteNameHelper() if (_context.ContextType == ContextType.Array) { var index = _context.Index++; - var nameBytes = ArrayElementNameAccelerator.Default.GetElementNameBytes(index); - _bsonStream.WriteCStringBytes(nameBytes); + Utf8Formatter.TryFormat(index, _temp10Bytes.AsSpan(), out var bytesWritten); + _bsonStream.WriteCStringBytes(new ArraySegment(_temp10Bytes, 0, bytesWritten)); } else { diff --git a/src/MongoDB.Bson/IO/BsonStream.cs b/src/MongoDB.Bson/IO/BsonStream.cs index 20268155c38..fc309254fef 100644 --- a/src/MongoDB.Bson/IO/BsonStream.cs +++ b/src/MongoDB.Bson/IO/BsonStream.cs @@ -100,6 +100,12 @@ public abstract class BsonStream : Stream /// The value. public abstract void WriteCStringBytes(byte[] value); + /// + /// Writes the CString bytes to the stream. + /// + /// + public abstract void WriteCStringBytes(ArraySegment value); + /// /// Writes a BSON Decimal128 to the stream. /// diff --git a/src/MongoDB.Bson/IO/BsonStreamAdapter.cs b/src/MongoDB.Bson/IO/BsonStreamAdapter.cs index 26acf64939a..ebb187bea37 100644 --- a/src/MongoDB.Bson/IO/BsonStreamAdapter.cs +++ b/src/MongoDB.Bson/IO/BsonStreamAdapter.cs @@ -483,6 +483,15 @@ public override void WriteCStringBytes(byte[] value) WriteByte(0); } + /// + public override void WriteCStringBytes(ArraySegment value) + { + ThrowIfDisposed(); + + this.WriteBytes(value.Array, value.Offset, value.Count); + WriteByte(0); + } + /// public override void WriteDecimal128(Decimal128 value) { diff --git a/src/MongoDB.Bson/IO/ByteBufferStream.cs b/src/MongoDB.Bson/IO/ByteBufferStream.cs index eddc84df2bf..dc20a07277f 100644 --- a/src/MongoDB.Bson/IO/ByteBufferStream.cs +++ b/src/MongoDB.Bson/IO/ByteBufferStream.cs @@ -572,7 +572,7 @@ public override void WriteCString(string value) { // Compare to 128 to preserve original behavior const int maxLengthToUseCStringUtf8EncodingWith = 128; - + if (maxLength <= maxLengthToUseCStringUtf8EncodingWith) { using var rentedBuffer = ThreadStaticBuffer.RentBuffer(maxLengthToUseCStringUtf8EncodingWith); @@ -623,6 +623,21 @@ public override void WriteCStringBytes(byte[] value) SetPositionAfterWrite(_position + length + 1); } + /// + public override void WriteCStringBytes(ArraySegment value) + { + ThrowIfDisposed(); + + var length = value.Count; + + PrepareToWrite(length + 1); + + _buffer.SetBytes(_position, value.Array, value.Offset, length); + _buffer.SetByte(_position + length, 0); + + SetPositionAfterWrite(_position + length + 1); + } + /// public override void WriteDecimal128(Decimal128 value) { diff --git a/tests/MongoDB.Bson.TestHelpers/IO/NullBsonStream.cs b/tests/MongoDB.Bson.TestHelpers/IO/NullBsonStream.cs index 135be71230a..ff16c538b5d 100644 --- a/tests/MongoDB.Bson.TestHelpers/IO/NullBsonStream.cs +++ b/tests/MongoDB.Bson.TestHelpers/IO/NullBsonStream.cs @@ -158,6 +158,11 @@ public override void WriteCStringBytes(byte[] value) Position += value.Length + 1; } + public override void WriteCStringBytes(ArraySegment value) + { + Position += value.Count + 1; + } + public override void WriteDecimal128(Decimal128 value) { Position += 16;