From e3d4a4f9c417716e79dc9c842cd485dafb6d06b0 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Tue, 27 Feb 2024 18:23:58 -0500 Subject: [PATCH] perf(NODE-5955): use pooled memory when possible --- src/bson.ts | 2 +- src/decimal128.ts | 2 +- src/objectid.ts | 2 +- src/parser/deserializer.ts | 24 +++++++++++------------- src/utils/byte_utils.ts | 2 ++ src/utils/node_byte_utils.ts | 5 +++++ src/utils/web_byte_utils.ts | 4 ++++ 7 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/bson.ts b/src/bson.ts index 64b433ca8..5b079291c 100644 --- a/src/bson.ts +++ b/src/bson.ts @@ -116,7 +116,7 @@ export function serialize(object: Document, options: SerializeOptions = {}): Uin ); // Create the final buffer - const finishedBuffer = ByteUtils.allocate(serializationIndex); + const finishedBuffer = ByteUtils.allocateUnsafe(serializationIndex); // Copy into the finished buffer finishedBuffer.set(buffer.subarray(0, serializationIndex), 0); diff --git a/src/decimal128.ts b/src/decimal128.ts index dc96f9cd1..806938e30 100644 --- a/src/decimal128.ts +++ b/src/decimal128.ts @@ -591,7 +591,7 @@ export class Decimal128 extends BSONValue { } // Encode into a buffer - const buffer = ByteUtils.allocate(16); + const buffer = ByteUtils.allocateUnsafe(16); index = 0; // Encode the low 64 bits of the decimal diff --git a/src/objectid.ts b/src/objectid.ts index 09ccd0ffa..98daecc88 100644 --- a/src/objectid.ts +++ b/src/objectid.ts @@ -177,7 +177,7 @@ export class ObjectId extends BSONValue { } const inc = ObjectId.getInc(); - const buffer = ByteUtils.allocate(12); + const buffer = ByteUtils.allocateUnsafe(12); // 4-byte timestamp NumberUtils.setInt32BE(buffer, 0, time); diff --git a/src/parser/deserializer.ts b/src/parser/deserializer.ts index 004f5bb1a..ac2781903 100644 --- a/src/parser/deserializer.ts +++ b/src/parser/deserializer.ts @@ -264,8 +264,8 @@ function deserializeObject( value = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey); index = index + stringSize; } else if (elementType === constants.BSON_DATA_OID) { - const oid = ByteUtils.allocate(12); - oid.set(buffer.subarray(index, index + 12)); + const oid = ByteUtils.allocateUnsafe(12); + for (let i = 0; i < 12; i++) oid[i] = buffer[index + i]; value = new ObjectId(oid); index = index + 12; } else if (elementType === constants.BSON_DATA_INT && promoteValues === false) { @@ -355,9 +355,9 @@ function deserializeObject( } } else if (elementType === constants.BSON_DATA_DECIMAL128) { // Buffer to contain the decimal bytes - const bytes = ByteUtils.allocate(16); + const bytes = ByteUtils.allocateUnsafe(16); // Copy the next 16 bytes into the bytes buffer - bytes.set(buffer.subarray(index, index + 16), 0); + for (let i = 0; i < 16; i++) bytes[i] = buffer[index + i]; // Update index index = index + 16; // Assign the new Decimal128 value @@ -398,7 +398,6 @@ function deserializeObject( } } } else { - const _buffer = ByteUtils.allocate(binarySize); // If we have subtype 2 skip the 4 bytes for the size if (subType === Binary.SUBTYPE_BYTE_ARRAY) { binarySize = NumberUtils.getInt32LE(buffer, index); @@ -411,13 +410,12 @@ function deserializeObject( throw new BSONError('Binary type with subtype 0x02 contains too short binary size'); } - // Copy the data - for (i = 0; i < binarySize; i++) { - _buffer[i] = buffer[index + i]; - } - if (promoteBuffers && promoteValues) { - value = _buffer; + value = ByteUtils.allocateUnsafe(binarySize); + // Copy the data + for (i = 0; i < binarySize; i++) { + value[i] = buffer[index + i]; + } } else { value = new Binary(buffer.slice(index, index + binarySize), subType); if (subType === constants.BSON_BINARY_SUBTYPE_UUID_NEW && UUID.isValid(value)) { @@ -616,8 +614,8 @@ function deserializeObject( index = index + stringSize; // Read the oid - const oidBuffer = ByteUtils.allocate(12); - oidBuffer.set(buffer.subarray(index, index + 12), 0); + const oidBuffer = ByteUtils.allocateUnsafe(12); + for (let i = 0; i < 12; i++) oidBuffer[i] = buffer[index + i]; const oid = new ObjectId(oidBuffer); // Update the index diff --git a/src/utils/byte_utils.ts b/src/utils/byte_utils.ts index e4c51dcf4..9c748acb4 100644 --- a/src/utils/byte_utils.ts +++ b/src/utils/byte_utils.ts @@ -7,6 +7,8 @@ export type ByteUtils = { toLocalBufferType(buffer: Uint8Array | ArrayBufferView | ArrayBuffer): Uint8Array; /** Create empty space of size */ allocate: (size: number) => Uint8Array; + /** Create empty space of size, use pooled memory when available */ + allocateUnsafe: (size: number) => Uint8Array; /** Check if two Uint8Arrays are deep equal */ equals: (a: Uint8Array, b: Uint8Array) => boolean; /** Check if two Uint8Arrays are deep equal */ diff --git a/src/utils/node_byte_utils.ts b/src/utils/node_byte_utils.ts index 519fad2ff..d6a641a47 100644 --- a/src/utils/node_byte_utils.ts +++ b/src/utils/node_byte_utils.ts @@ -12,6 +12,7 @@ type NodeJsBuffer = ArrayBufferView & }; type NodeJsBufferConstructor = Omit & { alloc: (size: number) => NodeJsBuffer; + allocUnsafe: (size: number) => NodeJsBuffer; from(array: number[]): NodeJsBuffer; from(array: Uint8Array): NodeJsBuffer; from(array: ArrayBuffer): NodeJsBuffer; @@ -89,6 +90,10 @@ export const nodeJsByteUtils = { return Buffer.alloc(size); }, + allocateUnsafe(size: number): NodeJsBuffer { + return Buffer.allocUnsafe(size); + }, + equals(a: Uint8Array, b: Uint8Array): boolean { return nodeJsByteUtils.toLocalBufferType(a).equals(b); }, diff --git a/src/utils/web_byte_utils.ts b/src/utils/web_byte_utils.ts index 62ae589ef..77a1f0f74 100644 --- a/src/utils/web_byte_utils.ts +++ b/src/utils/web_byte_utils.ts @@ -109,6 +109,10 @@ export const webByteUtils = { return new Uint8Array(size); }, + allocateUnsafe(size: number): Uint8Array { + return webByteUtils.allocate(size); + }, + equals(a: Uint8Array, b: Uint8Array): boolean { if (a.byteLength !== b.byteLength) { return false;