From dd6f534ad71711e8bca219c391101f0d601c040f Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Thu, 22 Feb 2024 18:30:57 -0500 Subject: [PATCH] perf(NODE-5910): optimize small byte copies --- src/objectid.ts | 17 ++++++++++++++++ src/parser/serializer.ts | 26 ++++++++++++------------- test/node/object_id.test.ts | 39 +++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/src/objectid.ts b/src/objectid.ts index b448f61b2..69c2a24f0 100644 --- a/src/objectid.ts +++ b/src/objectid.ts @@ -269,6 +269,23 @@ export class ObjectId extends BSONValue { return new ObjectId(); } + /** @internal */ + serializeInto(uint8array: Uint8Array, index: number): 12 { + uint8array[index] = this.buffer[0]; + uint8array[index + 1] = this.buffer[1]; + uint8array[index + 2] = this.buffer[2]; + uint8array[index + 3] = this.buffer[3]; + uint8array[index + 4] = this.buffer[4]; + uint8array[index + 5] = this.buffer[5]; + uint8array[index + 6] = this.buffer[6]; + uint8array[index + 7] = this.buffer[7]; + uint8array[index + 8] = this.buffer[8]; + uint8array[index + 9] = this.buffer[9]; + uint8array[index + 10] = this.buffer[10]; + uint8array[index + 11] = this.buffer[11]; + return 12; + } + /** * Creates an ObjectId from a second based number, with the rest of the ObjectId zeroed out. Used for comparisons or sorting the ObjectId. * diff --git a/src/parser/serializer.ts b/src/parser/serializer.ts index f5f562266..0c6ddcea6 100644 --- a/src/parser/serializer.ts +++ b/src/parser/serializer.ts @@ -256,16 +256,7 @@ function serializeObjectId(buffer: Uint8Array, key: string, value: ObjectId, ind index = index + numberOfWrittenBytes; buffer[index++] = 0; - // Write the objectId into the shared buffer - const idValue = value.id; - - if (isUint8Array(idValue)) { - for (let i = 0; i < 12; i++) { - buffer[index++] = idValue[i]; - } - } else { - throw new BSONError('object [' + JSON.stringify(value) + '] is not a valid ObjectId'); - } + index += value.serializeInto(buffer, index); // Adjust index return index; @@ -289,7 +280,11 @@ function serializeBuffer(buffer: Uint8Array, key: string, value: Uint8Array, ind // Write the default subtype buffer[index++] = constants.BSON_BINARY_SUBTYPE_DEFAULT; // Copy the content form the binary field to the buffer - buffer.set(value, index); + if (size <= 16) { + for (let i = 0; i < size; i++) buffer[index + i] = value[i]; + } else { + buffer.set(value, index); + } // Adjust the index index = index + size; return index; @@ -343,7 +338,7 @@ function serializeDecimal128(buffer: Uint8Array, key: string, value: Decimal128, index = index + numberOfWrittenBytes; buffer[index++] = 0; // Write the data from the value - buffer.set(value.bytes.subarray(0, 16), index); + for (let i = 0; i < 16; i++) buffer[index + i] = value.bytes[i]; return index + 16; } @@ -552,8 +547,11 @@ function serializeBinary(buffer: Uint8Array, key: string, value: Binary, index: buffer[index++] = (size >> 24) & 0xff; } - // Write the data to the object - buffer.set(data, index); + if (size <= 16) { + for (let i = 0; i < size; i++) buffer[index + i] = data[i]; + } else { + buffer.set(data, index); + } // Adjust the index index = index + value.position; return index; diff --git a/test/node/object_id.test.ts b/test/node/object_id.test.ts index 2af8b1326..62344c3a6 100644 --- a/test/node/object_id.test.ts +++ b/test/node/object_id.test.ts @@ -485,4 +485,43 @@ describe('ObjectId', function () { }); }); }); + + context('serializeInto()', () => { + it('writes oid bytes to input buffer', () => { + const oid = new ObjectId('61'.repeat(12)); + const buffer = new Uint8Array(20); + // @ts-expect-error: internal method + oid.serializeInto(buffer, 0); + expect(buffer.subarray(0, 12)).to.deep.equal(Buffer.from('61'.repeat(12), 'hex')); + }); + + it('writes oid bytes to input buffer at offset', () => { + const oid = new ObjectId('61'.repeat(12)); + const buffer = new Uint8Array(20); + // @ts-expect-error: internal method + oid.serializeInto(buffer, 5); + expect(buffer.subarray(5, 5 + 12)).to.deep.equal(Buffer.from('61'.repeat(12), 'hex')); + }); + + it('does not validate input types', () => { + const oid = new ObjectId('61'.repeat(12)); + const object = {}; + // @ts-expect-error: internal method + oid.serializeInto(object, 'b'); + expect(object).to.deep.equal({ + b: 0x61, + b1: 0x61, + b2: 0x61, + b3: 0x61, + b4: 0x61, + b5: 0x61, + b6: 0x61, + b7: 0x61, + b8: 0x61, + b9: 0x61, + b10: 0x61, + b11: 0x61 + }); + }); + }); });