Skip to content

Commit 24d035e

Browse files
authoredFeb 27, 2024··
perf(NODE-5910): optimize small byte copies (#651)
1 parent f53db84 commit 24d035e

File tree

3 files changed

+68
-14
lines changed

3 files changed

+68
-14
lines changed
 

‎src/objectid.ts

+17
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,23 @@ export class ObjectId extends BSONValue {
269269
return new ObjectId();
270270
}
271271

272+
/** @internal */
273+
serializeInto(uint8array: Uint8Array, index: number): 12 {
274+
uint8array[index] = this.buffer[0];
275+
uint8array[index + 1] = this.buffer[1];
276+
uint8array[index + 2] = this.buffer[2];
277+
uint8array[index + 3] = this.buffer[3];
278+
uint8array[index + 4] = this.buffer[4];
279+
uint8array[index + 5] = this.buffer[5];
280+
uint8array[index + 6] = this.buffer[6];
281+
uint8array[index + 7] = this.buffer[7];
282+
uint8array[index + 8] = this.buffer[8];
283+
uint8array[index + 9] = this.buffer[9];
284+
uint8array[index + 10] = this.buffer[10];
285+
uint8array[index + 11] = this.buffer[11];
286+
return 12;
287+
}
288+
272289
/**
273290
* Creates an ObjectId from a second based number, with the rest of the ObjectId zeroed out. Used for comparisons or sorting the ObjectId.
274291
*

‎src/parser/serializer.ts

+12-14
Original file line numberDiff line numberDiff line change
@@ -256,16 +256,7 @@ function serializeObjectId(buffer: Uint8Array, key: string, value: ObjectId, ind
256256
index = index + numberOfWrittenBytes;
257257
buffer[index++] = 0;
258258

259-
// Write the objectId into the shared buffer
260-
const idValue = value.id;
261-
262-
if (isUint8Array(idValue)) {
263-
for (let i = 0; i < 12; i++) {
264-
buffer[index++] = idValue[i];
265-
}
266-
} else {
267-
throw new BSONError('object [' + JSON.stringify(value) + '] is not a valid ObjectId');
268-
}
259+
index += value.serializeInto(buffer, index);
269260

270261
// Adjust index
271262
return index;
@@ -289,7 +280,11 @@ function serializeBuffer(buffer: Uint8Array, key: string, value: Uint8Array, ind
289280
// Write the default subtype
290281
buffer[index++] = constants.BSON_BINARY_SUBTYPE_DEFAULT;
291282
// Copy the content form the binary field to the buffer
292-
buffer.set(value, index);
283+
if (size <= 16) {
284+
for (let i = 0; i < size; i++) buffer[index + i] = value[i];
285+
} else {
286+
buffer.set(value, index);
287+
}
293288
// Adjust the index
294289
index = index + size;
295290
return index;
@@ -343,7 +338,7 @@ function serializeDecimal128(buffer: Uint8Array, key: string, value: Decimal128,
343338
index = index + numberOfWrittenBytes;
344339
buffer[index++] = 0;
345340
// Write the data from the value
346-
buffer.set(value.bytes.subarray(0, 16), index);
341+
for (let i = 0; i < 16; i++) buffer[index + i] = value.bytes[i];
347342
return index + 16;
348343
}
349344

@@ -552,8 +547,11 @@ function serializeBinary(buffer: Uint8Array, key: string, value: Binary, index:
552547
buffer[index++] = (size >> 24) & 0xff;
553548
}
554549

555-
// Write the data to the object
556-
buffer.set(data, index);
550+
if (size <= 16) {
551+
for (let i = 0; i < size; i++) buffer[index + i] = data[i];
552+
} else {
553+
buffer.set(data, index);
554+
}
557555
// Adjust the index
558556
index = index + value.position;
559557
return index;

‎test/node/object_id.test.ts

+39
Original file line numberDiff line numberDiff line change
@@ -485,4 +485,43 @@ describe('ObjectId', function () {
485485
});
486486
});
487487
});
488+
489+
context('serializeInto()', () => {
490+
it('writes oid bytes to input buffer', () => {
491+
const oid = new ObjectId('61'.repeat(12));
492+
const buffer = new Uint8Array(20);
493+
// @ts-expect-error: internal method
494+
oid.serializeInto(buffer, 0);
495+
expect(buffer.subarray(0, 12)).to.deep.equal(Buffer.from('61'.repeat(12), 'hex'));
496+
});
497+
498+
it('writes oid bytes to input buffer at offset', () => {
499+
const oid = new ObjectId('61'.repeat(12));
500+
const buffer = new Uint8Array(20);
501+
// @ts-expect-error: internal method
502+
oid.serializeInto(buffer, 5);
503+
expect(buffer.subarray(5, 5 + 12)).to.deep.equal(Buffer.from('61'.repeat(12), 'hex'));
504+
});
505+
506+
it('does not validate input types', () => {
507+
const oid = new ObjectId('61'.repeat(12));
508+
const object = {};
509+
// @ts-expect-error: internal method
510+
oid.serializeInto(object, 'b');
511+
expect(object).to.deep.equal({
512+
b: 0x61,
513+
b1: 0x61,
514+
b2: 0x61,
515+
b3: 0x61,
516+
b4: 0x61,
517+
b5: 0x61,
518+
b6: 0x61,
519+
b7: 0x61,
520+
b8: 0x61,
521+
b9: 0x61,
522+
b10: 0x61,
523+
b11: 0x61
524+
});
525+
});
526+
});
488527
});

0 commit comments

Comments
 (0)
Please sign in to comment.