Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(NODE-5910): optimize small byte copies #651

Merged
merged 1 commit into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/objectid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
26 changes: 12 additions & 14 deletions src/parser/serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down
39 changes: 39 additions & 0 deletions test/node/object_id.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
});
});
});
});