Skip to content

Commit ae2e037

Browse files
fix(NODE-7307): Replace node:process.hrtime() with performance.now() (#4816)
1 parent a96fa26 commit ae2e037

File tree

13 files changed

+88
-76
lines changed

13 files changed

+88
-76
lines changed

etc/sdam_viz.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// npx ts-node etc/sdam_viz.js -h
66

77
const { MongoClient } = require('../src');
8-
const { now, calculateDurationInMs, arrayStrictEqual, errorStrictEqual } = require('../src/utils');
8+
const { calculateDurationInMs, arrayStrictEqual, errorStrictEqual, processTimeMS } = require('../src/utils');
99

1010
const util = require('util');
1111
const chalk = require('chalk');
@@ -207,7 +207,7 @@ async function scheduleWriteWorkload(client) {
207207
const currentWriteWorkload = writeWorkloadCounter++;
208208

209209
try {
210-
const start = now();
210+
const start = processTimeMS();
211211
await client.db('test').collection('test').insertOne({ a: 42 });
212212
averageWriteMS = 0.2 * calculateDurationInMs(start) + 0.8 * averageWriteMS;
213213

src/cmap/connection.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ import {
4747
maxWireVersion,
4848
type MongoDBNamespace,
4949
noop,
50-
now,
5150
once,
51+
processTimeMS,
5252
squashError,
5353
uuidV4
5454
} from '../utils';
@@ -241,7 +241,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
241241

242242
this.description = new StreamDescription(this.address, options);
243243
this.generation = options.generation;
244-
this.lastUseTime = now();
244+
this.lastUseTime = processTimeMS();
245245

246246
this.messageStream = this.socket
247247
.on('error', this.onSocketError.bind(this))
@@ -299,7 +299,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
299299
}
300300

301301
public markAvailable(): void {
302-
this.lastUseTime = now();
302+
this.lastUseTime = processTimeMS();
303303
}
304304

305305
private onSocketError(cause: Error) {
@@ -510,7 +510,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
510510
const message = this.prepareCommand(ns.db, command, options);
511511
let started = 0;
512512
if (this.shouldEmitAndLogCommand) {
513-
started = now();
513+
started = processTimeMS();
514514
this.emitAndLogCommand(
515515
this.monitorCommands,
516516
Connection.COMMAND_STARTED,

src/cmap/connection_pool.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {
3636
List,
3737
makeCounter,
3838
noop,
39-
now,
39+
processTimeMS,
4040
promiseWithResolvers
4141
} from '../utils';
4242
import { connect } from './connect';
@@ -319,7 +319,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
319319
* explicitly destroyed by the new owner.
320320
*/
321321
async checkOut(options: { timeoutContext: TimeoutContext } & Abortable): Promise<Connection> {
322-
const checkoutTime = now();
322+
const checkoutTime = processTimeMS();
323323
this.emitAndLog(
324324
ConnectionPool.CONNECTION_CHECK_OUT_STARTED,
325325
new ConnectionCheckOutStartedEvent(this)
@@ -616,7 +616,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
616616

617617
this.pending++;
618618
// This is our version of a "virtual" no-I/O connection as the spec requires
619-
const connectionCreatedTime = now();
619+
const connectionCreatedTime = processTimeMS();
620620
this.emitAndLog(
621621
ConnectionPool.CONNECTION_CREATED,
622622
new ConnectionCreatedEvent(this, { id: connectOptions.id })

src/cmap/connection_pool_events.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
CONNECTION_READY
1414
} from '../constants';
1515
import type { MongoError } from '../error';
16-
import { now } from '../utils';
16+
import { processTimeMS } from '../utils';
1717
import type { Connection } from './connection';
1818
import type { ConnectionPool, ConnectionPoolOptions } from './connection_pool';
1919

@@ -145,7 +145,7 @@ export class ConnectionReadyEvent extends ConnectionPoolMonitoringEvent {
145145
/** @internal */
146146
constructor(pool: ConnectionPool, connection: Connection, connectionCreatedEventTime: number) {
147147
super(pool);
148-
this.durationMS = now() - connectionCreatedEventTime;
148+
this.durationMS = processTimeMS() - connectionCreatedEventTime;
149149
this.connectionId = connection.id;
150150
}
151151
}
@@ -224,7 +224,7 @@ export class ConnectionCheckOutFailedEvent extends ConnectionPoolMonitoringEvent
224224
error?: MongoError
225225
) {
226226
super(pool);
227-
this.durationMS = now() - checkoutTime;
227+
this.durationMS = processTimeMS() - checkoutTime;
228228
this.reason = reason;
229229
this.error = error;
230230
}
@@ -252,7 +252,7 @@ export class ConnectionCheckedOutEvent extends ConnectionPoolMonitoringEvent {
252252
/** @internal */
253253
constructor(pool: ConnectionPool, connection: Connection, checkoutTime: number) {
254254
super(pool);
255-
this.durationMS = now() - checkoutTime;
255+
this.durationMS = processTimeMS() - checkoutTime;
256256
this.connectionId = connection.id;
257257
}
258258
}

src/sdam/monitor.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import {
1414
type EventEmitterWithState,
1515
makeStateMachine,
1616
noop,
17-
now,
18-
ns
17+
ns,
18+
processTimeMS
1919
} from '../utils';
2020
import { ServerType, STATE_CLOSED, STATE_CLOSING } from './common';
2121
import {
@@ -326,7 +326,7 @@ function checkServer(monitor: Monitor, callback: Callback<Document | null>) {
326326
);
327327
// We have not actually sent an outgoing handshake, but when we get the next response we
328328
// want the duration to reflect the time since we last heard from the server
329-
start = now();
329+
start = processTimeMS();
330330
} else {
331331
monitor.rttPinger?.close();
332332
monitor.rttPinger = undefined;
@@ -360,7 +360,7 @@ function checkServer(monitor: Monitor, callback: Callback<Document | null>) {
360360
}
361361

362362
// Record new start time before sending handshake
363-
start = now();
363+
start = processTimeMS();
364364

365365
if (isAwaitable) {
366366
awaited = true;
@@ -383,7 +383,7 @@ function checkServer(monitor: Monitor, callback: Callback<Document | null>) {
383383
const socket = await makeSocket(monitor.connectOptions);
384384
const connection = makeConnection(monitor.connectOptions, socket);
385385
// The start time is after socket creation but before the handshake
386-
start = now();
386+
start = processTimeMS();
387387
try {
388388
await performInitialHandshake(connection, monitor.connectOptions);
389389
return connection;
@@ -532,7 +532,7 @@ export class RTTPinger {
532532
}
533533

534534
private measureRoundTripTime() {
535-
const start = now();
535+
const start = processTimeMS();
536536

537537
if (this.closed) {
538538
return;
@@ -607,7 +607,7 @@ export class MonitorInterval {
607607
}
608608

609609
wake() {
610-
const currentTime = now();
610+
const currentTime = processTimeMS();
611611
const timeSinceLastCall = currentTime - this.lastExecutionEnded;
612612

613613
// TODO(NODE-4674): Add error handling and logging to the monitor
@@ -651,7 +651,7 @@ export class MonitorInterval {
651651
}
652652

653653
toJSON() {
654-
const currentTime = now();
654+
const currentTime = processTimeMS();
655655
const timeSinceLastCall = currentTime - this.lastExecutionEnded;
656656
return {
657657
timerId: this.timerId != null ? 'set' : 'cleared',
@@ -684,7 +684,7 @@ export class MonitorInterval {
684684
this.isExecutionInProgress = true;
685685

686686
this.fn(() => {
687-
this.lastExecutionEnded = now();
687+
this.lastExecutionEnded = processTimeMS();
688688
this.isExecutionInProgress = false;
689689
this._reschedule(this.heartbeatFrequencyMS);
690690
});

src/sdam/server_description.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { type Document, Long, type ObjectId } from '../bson';
22
import { type MongoError, MongoRuntimeError } from '../error';
3-
import { arrayStrictEqual, compareObjectId, errorStrictEqual, HostAddress, now } from '../utils';
3+
import {
4+
arrayStrictEqual,
5+
compareObjectId,
6+
errorStrictEqual,
7+
HostAddress,
8+
processTimeMS
9+
} from '../utils';
410
import { type ClusterTime, ServerType } from './common';
511

612
const WRITABLE_SERVER_TYPES = new Set<ServerType>([
@@ -110,7 +116,7 @@ export class ServerDescription {
110116
this.maxWireVersion = hello?.maxWireVersion ?? 0;
111117
this.roundTripTime = options?.roundTripTime ?? -1;
112118
this.minRoundTripTime = options?.minRoundTripTime ?? 0;
113-
this.lastUpdateTime = now();
119+
this.lastUpdateTime = processTimeMS();
114120
this.lastWriteDate = hello?.lastWrite?.lastWriteDate ?? 0;
115121
// NOTE: This actually builds the stack string instead of holding onto the getter and all its
116122
// associated references. This is done to prevent a memory leak.

src/sdam/topology.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import {
4545
List,
4646
makeStateMachine,
4747
noop,
48-
now,
48+
processTimeMS,
4949
promiseWithResolvers,
5050
shuffle
5151
} from '../utils';
@@ -602,7 +602,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
602602
resolve,
603603
reject,
604604
cancelled: false,
605-
startTime: now(),
605+
startTime: processTimeMS(),
606606
operationName: options.operationName,
607607
waitingLogged: false,
608608
previousServer: options.previousServer
@@ -1001,7 +1001,8 @@ function processWaitQueue(topology: Topology) {
10011001
waitQueueMember.serverSelector,
10021002
topology.description,
10031003
topology.s.serverSelectionTimeoutMS !== 0
1004-
? topology.s.serverSelectionTimeoutMS - (now() - waitQueueMember.startTime)
1004+
? topology.s.serverSelectionTimeoutMS -
1005+
(processTimeMS() - waitQueueMember.startTime)
10051006
: -1,
10061007
waitQueueMember.operationName
10071008
)

src/sessions.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import {
4242
List,
4343
MongoDBNamespace,
4444
noop,
45-
now,
45+
processTimeMS,
4646
squashError,
4747
uuidV4
4848
} from './utils';
@@ -726,7 +726,9 @@ export class ClientSession
726726
})
727727
: null;
728728

729-
const startTime = this.timeoutContext?.csotEnabled() ? this.timeoutContext.start : now();
729+
const startTime = this.timeoutContext?.csotEnabled()
730+
? this.timeoutContext.start
731+
: processTimeMS();
730732

731733
let committed = false;
732734
let result: any;
@@ -768,7 +770,7 @@ export class ClientSession
768770

769771
if (
770772
fnError.hasErrorLabel(MongoErrorLabel.TransientTransactionError) &&
771-
(this.timeoutContext != null || now() - startTime < MAX_TIMEOUT)
773+
(this.timeoutContext != null || processTimeMS() - startTime < MAX_TIMEOUT)
772774
) {
773775
continue;
774776
}
@@ -796,14 +798,14 @@ export class ClientSession
796798
if (
797799
!isMaxTimeMSExpiredError(commitError) &&
798800
commitError.hasErrorLabel(MongoErrorLabel.UnknownTransactionCommitResult) &&
799-
(this.timeoutContext != null || now() - startTime < MAX_TIMEOUT)
801+
(this.timeoutContext != null || processTimeMS() - startTime < MAX_TIMEOUT)
800802
) {
801803
continue;
802804
}
803805

804806
if (
805807
commitError.hasErrorLabel(MongoErrorLabel.TransientTransactionError) &&
806-
(this.timeoutContext != null || now() - startTime < MAX_TIMEOUT)
808+
(this.timeoutContext != null || processTimeMS() - startTime < MAX_TIMEOUT)
807809
) {
808810
break;
809811
}
@@ -943,7 +945,7 @@ export class ServerSession {
943945
return;
944946
}
945947
this.id = { id: new Binary(uuidV4(), Binary.SUBTYPE_UUID) };
946-
this.lastUse = now();
948+
this.lastUse = processTimeMS();
947949
this.txnNumber = 0;
948950
this.isDirty = false;
949951
}
@@ -1078,7 +1080,7 @@ export function applySession(
10781080
}
10791081

10801082
// mark the last use of this session, and apply the `lsid`
1081-
serverSession.lastUse = now();
1083+
serverSession.lastUse = processTimeMS();
10821084
command.lsid = serverSession.id;
10831085

10841086
const inTxnOrTxnCommand = session.inTransaction() || isTransactionCommand(command);

src/utils.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -434,10 +434,13 @@ export function makeStateMachine(stateTable: StateTable): StateTransitionFunctio
434434
};
435435
}
436436

437-
/** @internal */
438-
export function now(): number {
439-
const hrtime = process.hrtime();
440-
return Math.floor(hrtime[0] * 1000 + hrtime[1] / 1000000);
437+
/**
438+
* This function returns the number of milliseconds since an arbitrary point in time.
439+
* This function should only be used to measure time intervals.
440+
* @internal
441+
* */
442+
export function processTimeMS(): number {
443+
return Math.floor(performance.now());
441444
}
442445

443446
/** @internal */
@@ -446,7 +449,7 @@ export function calculateDurationInMs(started: number | undefined): number {
446449
return -1;
447450
}
448451

449-
const elapsed = now() - started;
452+
const elapsed = processTimeMS() - started;
450453
return elapsed < 0 ? 0 : elapsed;
451454
}
452455

0 commit comments

Comments
 (0)