From 7589e124e2b7670a037ea5bdc329c7ded81b4645 Mon Sep 17 00:00:00 2001 From: Sean Reece Date: Mon, 21 Oct 2024 10:18:06 -0400 Subject: [PATCH 1/7] Use lazy hex cache --- src/objectid.ts | 10 +++++----- test/node/bson_test.js | 7 ++++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/objectid.ts b/src/objectid.ts index e548aa81..2aac3dfd 100644 --- a/src/objectid.ts +++ b/src/objectid.ts @@ -32,7 +32,7 @@ export class ObjectId extends BSONValue { /** @internal */ private static index = Math.floor(Math.random() * 0xffffff); - static cacheHexString: boolean; + static cacheHexString: boolean = true; /** ObjectId Bytes @internal */ private buffer!: Uint8Array; @@ -111,6 +111,10 @@ export class ObjectId extends BSONValue { } else if (typeof workingId === 'string') { if (ObjectId.validateHexString(workingId)) { this.buffer = ByteUtils.fromHex(workingId); + // If we are caching the hex string + if (ObjectId.cacheHexString) { + this.__id = workingId; + } } else { throw new BSONError( 'input must be a 24 character hex string, 12 byte Uint8Array, or an integer' @@ -119,10 +123,6 @@ export class ObjectId extends BSONValue { } else { throw new BSONError('Argument passed in does not match the accepted types'); } - // If we are caching the hex string - if (ObjectId.cacheHexString) { - this.__id = ByteUtils.toHex(this.id); - } } /** diff --git a/test/node/bson_test.js b/test/node/bson_test.js index d7edc17f..f9f3acf8 100644 --- a/test/node/bson_test.js +++ b/test/node/bson_test.js @@ -1648,21 +1648,25 @@ describe('BSON', function () { it('ObjectId should have a correct cached representation of the hexString', function (done) { ObjectId.cacheHexString = true; var a = new ObjectId(); + a.toHexString(); var __id = a.__id; expect(__id).to.equal(a.toHexString()); // hexString a = new ObjectId(__id); + a.toHexString(); expect(__id).to.equal(a.toHexString()); // fromHexString a = ObjectId.createFromHexString(__id); + a.toHexString(); expect(a.__id).to.equal(a.toHexString()); expect(__id).to.equal(a.toHexString()); // number var genTime = a.generationTime; a = new ObjectId(genTime); + a.toHexString(); __id = a.__id; expect(__id).to.equal(a.toHexString()); @@ -1673,6 +1677,7 @@ describe('BSON', function () { // createFromTime a = ObjectId.createFromTime(genTime); + a.toHexString(); __id = a.__id; expect(__id).to.equal(a.toHexString()); ObjectId.cacheHexString = false; @@ -1861,7 +1866,7 @@ describe('BSON', function () { ); expect(inspect(code)).to.equal( /* eslint-disable */ -`new Code( + `new Code( 'function iLoveJavaScript() {\\n' + ' do {\\n' + " console.log('hello!');\\n" + From 7aa3883da5877f3c91201387a112644b0158fe25 Mon Sep 17 00:00:00 2001 From: Sean Reece Date: Wed, 23 Oct 2024 13:04:32 -0400 Subject: [PATCH 2/7] No default cacheHexString --- src/objectid.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objectid.ts b/src/objectid.ts index 2aac3dfd..e1765275 100644 --- a/src/objectid.ts +++ b/src/objectid.ts @@ -32,7 +32,7 @@ export class ObjectId extends BSONValue { /** @internal */ private static index = Math.floor(Math.random() * 0xffffff); - static cacheHexString: boolean = true; + static cacheHexString: boolean; /** ObjectId Bytes @internal */ private buffer!: Uint8Array; From 295cc723fd839498ea41db076463716a2ea5ca11 Mon Sep 17 00:00:00 2001 From: Sean Reece Date: Wed, 23 Oct 2024 13:09:27 -0400 Subject: [PATCH 3/7] Oops remove accidental formatting --- test/node/bson_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/node/bson_test.js b/test/node/bson_test.js index ebb4cc0e..363d41c7 100644 --- a/test/node/bson_test.js +++ b/test/node/bson_test.js @@ -1792,7 +1792,7 @@ describe('BSON', function () { ); expect(inspect(code)).to.equal( /* eslint-disable */ - `new Code( +`new Code( 'function iLoveJavaScript() {\\n' + ' do {\\n' + " console.log('hello!');\\n" + From 896061bb73d7b897c99342710d47b0a51f02b6ec Mon Sep 17 00:00:00 2001 From: Sean Reece Date: Wed, 13 Nov 2024 16:41:22 -0500 Subject: [PATCH 4/7] weakMap + tests --- src/objectid.ts | 24 ++++++++++++++--------- test/node/bson_test.js | 44 ++++++++++++++++++++++++++++-------------- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/objectid.ts b/src/objectid.ts index e1765275..4a262838 100644 --- a/src/objectid.ts +++ b/src/objectid.ts @@ -7,10 +7,12 @@ import { NumberUtils } from './utils/number_utils'; // Unique sequence for the current process (initialized on first use) let PROCESS_UNIQUE: Uint8Array | null = null; +/** ObjectId hexString cache @internal */ +const __idCache = new WeakMap(); // TODO convert this to #__id private field when target updated to ES2022 + /** @public */ export interface ObjectIdLike { id: string | Uint8Array; - __id?: string; toHexString(): string; } @@ -36,8 +38,6 @@ export class ObjectId extends BSONValue { /** ObjectId Bytes @internal */ private buffer!: Uint8Array; - /** ObjectId hexString cache @internal */ - private __id?: string; /** * Create ObjectId from a number. @@ -113,7 +113,7 @@ export class ObjectId extends BSONValue { this.buffer = ByteUtils.fromHex(workingId); // If we are caching the hex string if (ObjectId.cacheHexString) { - this.__id = workingId; + __idCache.set(this, workingId); } } else { throw new BSONError( @@ -136,7 +136,7 @@ export class ObjectId extends BSONValue { set id(value: Uint8Array) { this.buffer = value; if (ObjectId.cacheHexString) { - this.__id = ByteUtils.toHex(value); + __idCache.set(this, ByteUtils.toHex(value)); } } @@ -165,14 +165,15 @@ export class ObjectId extends BSONValue { /** Returns the ObjectId id as a 24 lowercase character hex string representation */ toHexString(): string { - if (ObjectId.cacheHexString && this.__id) { - return this.__id; + if (ObjectId.cacheHexString) { + const __id = __idCache.get(this); + if (__id) return __id; } const hexString = ByteUtils.toHex(this.id); - if (ObjectId.cacheHexString && !this.__id) { - this.__id = hexString; + if (ObjectId.cacheHexString) { + __idCache.set(this, hexString); } return hexString; @@ -370,6 +371,11 @@ export class ObjectId extends BSONValue { return new ObjectId(doc.$oid); } + /** @internal */ + private isCached(): boolean { + return ObjectId.cacheHexString && __idCache.has(this); + } + /** * Converts to a string representation of this Id. * diff --git a/test/node/bson_test.js b/test/node/bson_test.js index 363d41c7..2af4a7f7 100644 --- a/test/node/bson_test.js +++ b/test/node/bson_test.js @@ -1573,41 +1573,55 @@ describe('BSON', function () { */ it('ObjectId should have a correct cached representation of the hexString', function (done) { ObjectId.cacheHexString = true; + // generated ObjectID uses lazy caching var a = new ObjectId(); + expect(a.isCached()).to.be.false; a.toHexString(); - var __id = a.__id; - expect(__id).to.equal(a.toHexString()); + expect(a.isCached()).to.be.true; + expect(a.toHexString()).to.equal(a.toHexString()); - // hexString - a = new ObjectId(__id); + // hexString caches immediately + a = new ObjectId(a.toHexString()); + expect(a.isCached()).to.be.true; a.toHexString(); - expect(__id).to.equal(a.toHexString()); + expect(a.isCached()).to.be.true; + expect(a.toHexString()).to.equal(a.toHexString()); // fromHexString - a = ObjectId.createFromHexString(__id); + a = ObjectId.createFromHexString(a.toHexString()); + expect(a.isCached()).to.be.false; a.toHexString(); - expect(a.__id).to.equal(a.toHexString()); - expect(__id).to.equal(a.toHexString()); + expect(a.isCached()).to.be.true; + expect(a.toHexString()).to.equal(a.toHexString()); // number var genTime = a.generationTime; a = new ObjectId(genTime); + expect(a.isCached()).to.be.false; a.toHexString(); - __id = a.__id; - expect(__id).to.equal(a.toHexString()); + expect(a.isCached()).to.be.true; + expect(a.toHexString()).to.equal(a.toHexString()); // generationTime - delete a.__id; a.generationTime = genTime; - expect(__id).to.equal(a.toHexString()); + expect(a.isCached()).to.be.true; + expect(a.toHexString()).to.equal(a.toHexString()); // createFromTime a = ObjectId.createFromTime(genTime); + expect(a.isCached()).to.be.false; a.toHexString(); - __id = a.__id; - expect(__id).to.equal(a.toHexString()); + expect(a.isCached()).to.be.true; + expect(a.toHexString()).to.equal(a.toHexString()); + ObjectId.cacheHexString = false; + // No longer caches after cache is disabled + a = new ObjectId(); + expect(a.isCached()).to.be.false; + a.toHexString(); + expect(a.isCached()).to.be.false; + done(); }); @@ -1792,7 +1806,7 @@ describe('BSON', function () { ); expect(inspect(code)).to.equal( /* eslint-disable */ -`new Code( + `new Code( 'function iLoveJavaScript() {\\n' + ' do {\\n' + " console.log('hello!');\\n" + From a298eb5689451e2dd7d8d319ce57765fcacbbafb Mon Sep 17 00:00:00 2001 From: Sean Reece Date: Wed, 13 Nov 2024 16:47:47 -0500 Subject: [PATCH 5/7] Undo format --- test/node/bson_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/node/bson_test.js b/test/node/bson_test.js index 2af4a7f7..a996ddf3 100644 --- a/test/node/bson_test.js +++ b/test/node/bson_test.js @@ -1806,7 +1806,7 @@ describe('BSON', function () { ); expect(inspect(code)).to.equal( /* eslint-disable */ - `new Code( +`new Code( 'function iLoveJavaScript() {\\n' + ' do {\\n' + " console.log('hello!');\\n" + From c5c278be786d242e5934b2990a879a4aa2d535eb Mon Sep 17 00:00:00 2001 From: Sean Reece Date: Mon, 18 Nov 2024 13:09:29 -0500 Subject: [PATCH 6/7] Add __id back to interface --- src/objectid.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/objectid.ts b/src/objectid.ts index 4a262838..f2283bbe 100644 --- a/src/objectid.ts +++ b/src/objectid.ts @@ -13,6 +13,7 @@ const __idCache = new WeakMap(); // TODO convert this to #__id private field whe /** @public */ export interface ObjectIdLike { id: string | Uint8Array; + __id?: string; toHexString(): string; } From 890291904637680943a29bf414352e034d1fa40a Mon Sep 17 00:00:00 2001 From: Sean Reece Date: Mon, 18 Nov 2024 13:54:46 -0500 Subject: [PATCH 7/7] Update src/objectid.ts Co-authored-by: Bailey Pearson --- src/objectid.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objectid.ts b/src/objectid.ts index f2283bbe..a9abde9f 100644 --- a/src/objectid.ts +++ b/src/objectid.ts @@ -8,7 +8,7 @@ import { NumberUtils } from './utils/number_utils'; let PROCESS_UNIQUE: Uint8Array | null = null; /** ObjectId hexString cache @internal */ -const __idCache = new WeakMap(); // TODO convert this to #__id private field when target updated to ES2022 +const __idCache = new WeakMap(); // TODO(NODE-6549): convert this to #__id private field when target updated to ES2022 /** @public */ export interface ObjectIdLike {