Skip to content

Commit 87df765

Browse files
Merge branch 'main' into NODE-7311
2 parents 2e6d82c + f0af829 commit 87df765

3 files changed

Lines changed: 34 additions & 8 deletions

File tree

src/cmap/handshake/client_metadata.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ export async function makeClientMetadata(
158158
// Note: order matters, os.type is last so it will be removed last if we're at maxSize
159159
const osInfo = new Map()
160160
.set('name', os.platform())
161-
.set('architecture', process.arch)
161+
.set('architecture', os.arch())
162162
.set('version', os.release())
163163
.set('type', os.type());
164164

src/sessions.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,8 @@ export class ClientSession
726726
})
727727
: null;
728728

729-
const startTime = this.timeoutContext?.csotEnabled()
729+
// 1. Record the current monotonic time, which will be used to enforce the 120-second timeout before later retry attempts.
730+
const startTime = this.timeoutContext?.csotEnabled() // This is strictly to appease TS. We must narrow the context to a CSOT context before accessing `.start`.
730731
? this.timeoutContext.start
731732
: processTimeMS();
732733

@@ -735,9 +736,13 @@ export class ClientSession
735736

736737
try {
737738
while (!committed) {
739+
// 2. Invoke startTransaction on the session
740+
// 3. If `startTransaction` reported an error, propagate that error to the caller of `withTransaction` and return immediately.
738741
this.startTransaction(options); // may throw on error
739742

740743
try {
744+
// 4. Invoke the callback.
745+
// 5. Control returns to withTransaction. (continued below)
741746
const promise = fn(this);
742747
if (!isPromiseLike(promise)) {
743748
throw new MongoInvalidArgumentError(
@@ -747,16 +752,22 @@ export class ClientSession
747752

748753
result = await promise;
749754

755+
// 5. (cont.) Determine the current state of the ClientSession (continued below)
750756
if (
751757
this.transaction.state === TxnState.NO_TRANSACTION ||
752758
this.transaction.state === TxnState.TRANSACTION_COMMITTED ||
753759
this.transaction.state === TxnState.TRANSACTION_ABORTED
754760
) {
755-
// Assume callback intentionally ended the transaction
761+
// 7. If the ClientSession is in the "no transaction", "transaction aborted", or "transaction committed" state,
762+
// assume the callback intentionally aborted or committed the transaction and return immediately.
756763
return result;
757764
}
765+
// 5. (cont.) and whether the callback reported an error
766+
// 6. If the callback reported an error:
758767
} catch (fnError) {
759768
if (!(fnError instanceof MongoError) || fnError instanceof MongoInvalidArgumentError) {
769+
// This first preemptive abort regardless of TxnState isn't spec,
770+
// and it's unclear whether it's serving a practical purpose, but this logic is OLD
760771
await this.abortTransaction();
761772
throw fnError;
762773
}
@@ -765,16 +776,24 @@ export class ClientSession
765776
this.transaction.state === TxnState.STARTING_TRANSACTION ||
766777
this.transaction.state === TxnState.TRANSACTION_IN_PROGRESS
767778
) {
779+
// 6.i If the ClientSession is in the "starting transaction" or "transaction in progress" state,
780+
// invoke abortTransaction on the session
768781
await this.abortTransaction();
769782
}
770783

771784
if (
772785
fnError.hasErrorLabel(MongoErrorLabel.TransientTransactionError) &&
773786
(this.timeoutContext != null || processTimeMS() - startTime < MAX_TIMEOUT)
774787
) {
788+
// 6.ii If the callback's error includes a "TransientTransactionError" label and the elapsed time of `withTransaction`
789+
// is less than 120 seconds, jump back to step two.
775790
continue;
776791
}
777792

793+
// 6.iii If the callback's error includes a "UnknownTransactionCommitResult" label, the callback must have manually committed a transaction,
794+
// propagate the callback's error to the caller of withTransaction and return immediately.
795+
// The 6.iii check is redundant with 6.iv, so we don't write code for it
796+
// 6.iv Otherwise, propagate the callback's error to the caller of withTransaction and return immediately.
778797
throw fnError;
779798
}
780799

@@ -785,8 +804,10 @@ export class ClientSession
785804
* apply a majority write concern if commitTransaction is
786805
* being retried (see: DRIVERS-601)
787806
*/
807+
// 8. Invoke commitTransaction on the session.
788808
await this.commitTransaction();
789809
committed = true;
810+
// 9. If commitTransaction reported an error:
790811
} catch (commitError) {
791812
/*
792813
* Note: a maxTimeMS error will have the MaxTimeMSExpired
@@ -800,16 +821,21 @@ export class ClientSession
800821
commitError.hasErrorLabel(MongoErrorLabel.UnknownTransactionCommitResult) &&
801822
(this.timeoutContext != null || processTimeMS() - startTime < MAX_TIMEOUT)
802823
) {
824+
// 9.i If the `commitTransaction` error includes a "UnknownTransactionCommitResult" label and the error is not
825+
// MaxTimeMSExpired and the elapsed time of `withTransaction` is less than 120 seconds, jump back to step eight.
803826
continue;
804827
}
805828

806829
if (
807830
commitError.hasErrorLabel(MongoErrorLabel.TransientTransactionError) &&
808831
(this.timeoutContext != null || processTimeMS() - startTime < MAX_TIMEOUT)
809832
) {
833+
// 9.ii If the commitTransaction error includes a "TransientTransactionError" label
834+
// and the elapsed time of withTransaction is less than 120 seconds, jump back to step two.
810835
break;
811836
}
812837

838+
// 9.iii Otherwise, propagate the commitTransaction error to the caller of withTransaction and return immediately.
813839
throw commitError;
814840
}
815841
}

test/unit/cmap/handshake/client_metadata.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ describe('client metadata module', () => {
154154
os: {
155155
type: os.type(),
156156
name: os.platform(),
157-
architecture: process.arch,
157+
architecture: os.arch(),
158158
version: os.release()
159159
},
160160
platform: `Node.js ${process.version}, ${os.endianness()}`
@@ -180,7 +180,7 @@ describe('client metadata module', () => {
180180
os: {
181181
type: os.type(),
182182
name: os.platform(),
183-
architecture: process.arch,
183+
architecture: os.arch(),
184184
version: os.release()
185185
},
186186
platform: `Node.js ${process.version}, ${os.endianness()}|myPlatform`
@@ -204,7 +204,7 @@ describe('client metadata module', () => {
204204
os: {
205205
type: os.type(),
206206
name: os.platform(),
207-
architecture: process.arch,
207+
architecture: os.arch(),
208208
version: os.release()
209209
},
210210
platform: `Node.js ${process.version}, ${os.endianness()}`
@@ -230,7 +230,7 @@ describe('client metadata module', () => {
230230
os: {
231231
type: os.type(),
232232
name: os.platform(),
233-
architecture: process.arch,
233+
architecture: os.arch(),
234234
version: os.release()
235235
},
236236
platform: `Node.js ${process.version}, ${os.endianness()}`
@@ -249,7 +249,7 @@ describe('client metadata module', () => {
249249
os: {
250250
type: os.type(),
251251
name: os.platform(),
252-
architecture: process.arch,
252+
architecture: os.arch(),
253253
version: os.release()
254254
},
255255
platform: `Node.js ${process.version}, ${os.endianness()}`

0 commit comments

Comments
 (0)