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

feat(NODE-6305): Add CSOT support to tailable cursors #4218

Merged
merged 141 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
141 commits
Select commit Hold shift + click to select a range
d513fd6
feat(NODE-6090): Implement CSOT logic for connection checkout and ser…
W-A-James Apr 11, 2024
7d65aae
test(NODE-6120): Implement Unified test runner changes for CSOT (#4121)
W-A-James Jun 10, 2024
954e713
refactor(NODE-6187): refactor to use TimeoutContext abstraction (#4131)
W-A-James Jun 21, 2024
c5969b2
refactor(NODE-6230): executeOperation to use iterative retry mechanis…
nbbeeken Jul 22, 2024
8599cb3
feat(NODE-5682): set maxTimeMS on commands and preempt I/O (#4174)
nbbeeken Jul 26, 2024
7b9fa1f
feat(NODE-6231): Add CSOT behaviour for retryable reads and writes (#…
W-A-James Aug 1, 2024
260d679
feat(NODE-6312): add error transformation for server timeouts (#4192)
nbbeeken Aug 12, 2024
78eb356
add timeoutMode to find, findOne, listIndexes, aggregate, listCollect…
W-A-James Aug 14, 2024
a22784d
unskip spec tests
W-A-James Aug 14, 2024
6c423e0
implement prose tests
W-A-James Aug 14, 2024
978d8dd
Add timeoutMode to abstract cursor and add validation
W-A-James Aug 14, 2024
5317378
Add $out and $merge validation
W-A-James Aug 14, 2024
7c459e0
start csot cursor implementation
W-A-James Aug 15, 2024
0a2e4ce
WIP: int testing
W-A-James Aug 15, 2024
ac97b5a
WIP
W-A-James Aug 16, 2024
02f835e
fix test
W-A-James Aug 16, 2024
1e65e25
correctly propagate timeoutMode
W-A-James Aug 16, 2024
0bc7793
rework test skip logic
W-A-James Aug 16, 2024
f83d3ef
wip
W-A-James Aug 20, 2024
9549fd4
prose tests WIP
W-A-James Aug 20, 2024
173796b
put CSOT options on runCursorCommand
W-A-James Aug 20, 2024
9fc4c4e
finish up int tests
W-A-James Aug 20, 2024
507af55
timeoutContext refresh fix
W-A-James Aug 20, 2024
1f27040
apply CSOT to hasNext and tryNext
W-A-James Aug 20, 2024
af02eb8
sync spec tests
W-A-James Aug 21, 2024
679c02c
add omitMaxTimeMS
W-A-James Aug 21, 2024
abc1cfd
skipping spec tests
W-A-James Aug 21, 2024
b64af7b
pass through timeoutMS arg to cursor.close
W-A-James Aug 21, 2024
628eb55
Fix tests and dropindexes
W-A-James Aug 23, 2024
e90e7ed
add catch
W-A-James Aug 23, 2024
cbbd7e7
ensure that CSOT tests only run against 4.4 or greater
W-A-James Aug 26, 2024
fd43e60
lint
W-A-James Aug 26, 2024
bcb6e70
ignore
W-A-James Aug 26, 2024
2ac4b0f
update export test
W-A-James Aug 26, 2024
ba0dc00
remove TODO
W-A-James Aug 26, 2024
1fb6c7d
use cursorOptions instead of CursorInitializeOptions
W-A-James Aug 28, 2024
343829f
remove CursorInitializeOptions and fix export
W-A-James Aug 28, 2024
441f71d
Review fixes
W-A-James Aug 28, 2024
a9b4f02
fix setting of omitMaxTimeMS opts
W-A-James Aug 28, 2024
041b202
ensure that timeoutMS is provided to cursor.close in UTR
W-A-James Aug 28, 2024
cff3c3c
add modified spec test
W-A-James Aug 28, 2024
0488d50
remove redundant optional chaining
W-A-James Aug 28, 2024
4a6607f
remove cursorTimeoutMode from timeoutContext options
W-A-James Aug 28, 2024
96ecddc
remove types from expected exports
W-A-James Aug 28, 2024
504eec2
remove cursorTimeoutMode from TimeoutContext.create call
W-A-James Aug 29, 2024
cb810e2
review comments
W-A-James Sep 3, 2024
54286ae
lint
W-A-James Sep 3, 2024
9114290
type annotation and bracket reorganization
W-A-James Sep 3, 2024
a47337b
skip flaky test and replace with more consistent one
W-A-James Sep 4, 2024
3236c83
spec test fixes
W-A-James Sep 4, 2024
743b55f
lint
W-A-James Sep 4, 2024
5f4ba4c
unskip tailable cursor spec tests
W-A-James Aug 28, 2024
fe62afb
unskip prose test
W-A-James Aug 28, 2024
f6aa44b
WIP
W-A-James Aug 29, 2024
134259c
WIP
W-A-James Sep 3, 2024
5a30b84
update tests
W-A-James Sep 3, 2024
5eb53ca
WIP
W-A-James Sep 3, 2024
8e6069b
WIP
W-A-James Sep 4, 2024
f997eed
test fixes
W-A-James Sep 4, 2024
095234a
update spec runner
W-A-James Sep 4, 2024
2ec0219
unskip spec tests
W-A-James Sep 4, 2024
f98c095
WIP
W-A-James Sep 6, 2024
b5006de
WIP - updated spec test files
W-A-James Sep 6, 2024
c110bcb
change streams WIP
W-A-James Sep 6, 2024
3c2ec0a
feat(NODE-6090): Implement CSOT logic for connection checkout and ser…
W-A-James Apr 11, 2024
909578f
test(NODE-6120): Implement Unified test runner changes for CSOT (#4121)
W-A-James Jun 10, 2024
e101750
refactor(NODE-6187): refactor to use TimeoutContext abstraction (#4131)
W-A-James Jun 21, 2024
e4efd3f
refactor(NODE-6230): executeOperation to use iterative retry mechanis…
nbbeeken Jul 22, 2024
22082c9
feat(NODE-5682): set maxTimeMS on commands and preempt I/O (#4174)
nbbeeken Jul 26, 2024
bf95fa4
feat(NODE-6231): Add CSOT behaviour for retryable reads and writes (#…
W-A-James Aug 1, 2024
c63d102
feat(NODE-6312): add error transformation for server timeouts (#4192)
nbbeeken Aug 12, 2024
1eab23d
feat(NODE-6313): add CSOT support to sessions and transactions (#4199)
nbbeeken Sep 9, 2024
4c4b0a9
feat(NODE-6304): add CSOT support for non-tailable cursors (#4195)
W-A-James Sep 12, 2024
558d416
fix(NODE-6374): MongoOperationTimeoutError inherits MongoRuntimeError…
nbbeeken Sep 12, 2024
3ed4a14
test: remove empty skipped context blocks (#4238)
W-A-James Sep 12, 2024
45483b7
Merge branch 'NODE-6090' into NODE-6305
W-A-James Sep 16, 2024
ae83865
Revert "Merge branch 'NODE-6090' into NODE-6305"
W-A-James Sep 16, 2024
5045ec3
Reapply "Merge branch 'NODE-6090' into NODE-6305"
W-A-James Sep 16, 2024
d3438ea
feat(NODE-5844): add iscryptd to ServerDescription (#4239)
nbbeeken Sep 17, 2024
23c9cb1
resolve merge errors
W-A-James Sep 17, 2024
abe7827
resolve merge errors
W-A-James Sep 17, 2024
f7227a7
fixed tests
W-A-James Sep 17, 2024
7a400c7
lint
W-A-James Sep 17, 2024
9e90e13
unskip prose tests
W-A-James Sep 17, 2024
0fdeaa4
add new benchmarks
W-A-James Sep 17, 2024
6c127b9
do not add timeoutMS to create command
W-A-James Sep 17, 2024
fb87725
add todo
W-A-James Sep 17, 2024
2fde74c
Merge branch 'NODE-6090' into NODE-6305
W-A-James Sep 18, 2024
f5634e6
update prose test
W-A-James Sep 18, 2024
acbc170
skip change stream spec tests
W-A-James Sep 18, 2024
2c4aafb
create modified spec tests for coverage
W-A-James Sep 18, 2024
31b2115
update modified spec tests
W-A-James Sep 18, 2024
4ac2ece
cleanup
W-A-James Sep 18, 2024
6b12b6e
lint
W-A-James Sep 18, 2024
3233a66
lint
W-A-James Sep 18, 2024
10cc4bf
comment debug code
W-A-James Sep 18, 2024
588735b
revert change_stream changes
W-A-James Sep 18, 2024
a5d7dcc
revert changes to change_stream_cursor
W-A-James Sep 18, 2024
257540a
remove duplicated logic
W-A-James Sep 18, 2024
733980c
bump timeouts
W-A-James Sep 18, 2024
c66dc7f
change timeoutMS to match spec
W-A-James Sep 18, 2024
db47396
fix flaky tests
W-A-James Sep 19, 2024
77c4014
fix benchmarks
W-A-James Sep 19, 2024
93746b7
fix tests
W-A-James Sep 19, 2024
91b3948
review comments
W-A-James Sep 19, 2024
7a37fd8
review comments
W-A-James Sep 19, 2024
8901b67
enable CSOT by default for benchmarks
W-A-James Sep 19, 2024
88ea7df
lint
W-A-James Sep 19, 2024
eadcff3
skip test on incompatible server versions
W-A-James Sep 20, 2024
8b4c6fe
add test metadata
W-A-James Sep 20, 2024
609a550
lint
W-A-James Sep 20, 2024
999f23d
feat(NODE-6090): Implement CSOT logic for connection checkout and ser…
W-A-James Apr 11, 2024
0355404
test(NODE-6120): Implement Unified test runner changes for CSOT (#4121)
W-A-James Jun 10, 2024
5ef3d69
refactor(NODE-6187): refactor to use TimeoutContext abstraction (#4131)
W-A-James Jun 21, 2024
7139b8f
refactor(NODE-6230): executeOperation to use iterative retry mechanis…
nbbeeken Jul 22, 2024
acfb4fc
feat(NODE-5682): set maxTimeMS on commands and preempt I/O (#4174)
nbbeeken Jul 26, 2024
4efff95
feat(NODE-6231): Add CSOT behaviour for retryable reads and writes (#…
W-A-James Aug 1, 2024
1997f81
feat(NODE-6312): add error transformation for server timeouts (#4192)
nbbeeken Aug 12, 2024
cc3ef8f
feat(NODE-6313): add CSOT support to sessions and transactions (#4199)
nbbeeken Sep 9, 2024
38affae
feat(NODE-6304): add CSOT support for non-tailable cursors (#4195)
W-A-James Sep 12, 2024
738188b
fix(NODE-6374): MongoOperationTimeoutError inherits MongoRuntimeError…
nbbeeken Sep 12, 2024
c4a7c2c
test: remove empty skipped context blocks (#4238)
W-A-James Sep 12, 2024
5aa6d4c
feat(NODE-5844): add iscryptd to ServerDescription (#4239)
nbbeeken Sep 17, 2024
17a2fde
chore: allow clientBulkWrite to use TimeoutContext (#4251)
W-A-James Sep 25, 2024
1ed3132
Merge branch 'NODE-6090' into NODE-6305
W-A-James Sep 26, 2024
c29c4ab
lint
W-A-James Sep 26, 2024
1e58f14
lint
W-A-James Sep 26, 2024
2c1cb82
review comments
W-A-James Sep 27, 2024
05c3fcd
remove duplicated logic
W-A-James Sep 27, 2024
6aea417
add catch to dropCollection
W-A-James Sep 30, 2024
20d4b91
skip tests on < 4.4
W-A-James Sep 30, 2024
3cc81c2
Merge branch 'NODE-6090' into NODE-6305
W-A-James Oct 2, 2024
66b3dd5
reskip problematic tests on 4.4
W-A-James Oct 2, 2024
4918283
lint
W-A-James Oct 2, 2024
52227d6
Merge branch 'NODE-6090' into NODE-6305
W-A-James Oct 3, 2024
73c394b
Merge branch 'NODE-6090' into NODE-6305
W-A-James Oct 4, 2024
04e226a
fix merge conflict
W-A-James Oct 4, 2024
737b831
empty
W-A-James Oct 4, 2024
199003a
wait for bulk write to finish
W-A-James Oct 7, 2024
2b843b9
Merge branch 'NODE-6090' into NODE-6305
W-A-James Oct 7, 2024
7225b4e
use separate collection for bulk write test
W-A-James Oct 7, 2024
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
51 changes: 40 additions & 11 deletions src/cursor/abstract_cursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,35 @@ export abstract class AbstractCursor<
options.readPreference && options.readPreference instanceof ReadPreference
? options.readPreference
: ReadPreference.primary,
...pluckBSONSerializeOptions(options)
...pluckBSONSerializeOptions(options),
timeoutMS: options.timeoutMS,
tailable: options.tailable,
awaitData: options.awaitData
};
this.cursorOptions.timeoutMS = options.timeoutMS;
if (this.cursorOptions.timeoutMS != null) {
if (options.tailable && this.cursorOptions.timeoutMode === CursorTimeoutMode.LIFETIME) {
throw new MongoInvalidArgumentError("Cannot set tailable cursor's timeoutMode to LIFETIME");
if (options.timeoutMode == null) {
if (options.tailable) {
this.cursorOptions.timeoutMode = CursorTimeoutMode.ITERATION;

if (options.awaitData) {
if (
options.maxAwaitTimeMS != null &&
options.maxAwaitTimeMS >= this.cursorOptions.timeoutMS
)
throw new MongoInvalidArgumentError(
'Cannot specify maxAwaitTimeMS >= timeoutMS for a tailable awaitData cursor'
);
}
} else {
this.cursorOptions.timeoutMode = CursorTimeoutMode.LIFETIME;
}
} else {
if (options.tailable && this.cursorOptions.timeoutMode === CursorTimeoutMode.LIFETIME) {
throw new MongoInvalidArgumentError(
"Cannot set tailable cursor's timeoutMode to LIFETIME"
);
}
this.cursorOptions.timeoutMode = options.timeoutMode;
}
this.cursorOptions.timeoutMode =
options.timeoutMode ??
Expand All @@ -223,6 +246,8 @@ export abstract class AbstractCursor<
if (options.timeoutMode != null)
throw new MongoInvalidArgumentError('Cannot set timeoutMode without setting timeoutMS');
}

// Set for initial command
this.cursorOptions.omitMaxTimeMS =
this.cursorOptions.timeoutMS != null &&
((this.cursorOptions.timeoutMode === CursorTimeoutMode.ITERATION &&
Expand Down Expand Up @@ -781,15 +806,17 @@ export abstract class AbstractCursor<
'Unexpected null selectedServer. A cursor creating command should have set this'
);
}
const getMoreOptions = {
...this.cursorOptions,
session: this.cursorSession,
batchSize
};

const getMoreOperation = new GetMoreOperation(
this.cursorNamespace,
this.cursorId,
this.selectedServer,
{
...this.cursorOptions,
session: this.cursorSession,
batchSize
}
getMoreOptions
);

return await executeOperation(this.cursorClient, getMoreOperation, this.timeoutContext);
Expand All @@ -814,6 +841,8 @@ export abstract class AbstractCursor<
}
try {
const state = await this._initialize(this.cursorSession);
// Set omitMaxTimeMS to the value needed for subsequent getMore calls
this.cursorOptions.omitMaxTimeMS = this.cursorOptions.timeoutMS != null;
const response = state.response;
this.selectedServer = state.server;
this.cursorId = response.id;
Expand Down Expand Up @@ -866,9 +895,9 @@ export abstract class AbstractCursor<
} catch (error) {
try {
await this.cleanup(undefined, error);
} catch (error) {
} catch (cleanupError) {
// `cleanupCursor` should never throw, squash and throw the original error
squashError(error);
squashError(cleanupError);
}
throw error;
}
Expand Down
2 changes: 2 additions & 0 deletions src/cursor/run_command_cursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export type RunCursorCommandOptions = {
timeoutMS?: number;
/** @internal */
timeoutMode?: CursorTimeoutMode;
tailable?: boolean;
awaitData?: boolean;
} & BSONSerializeOptions;

/** @public */
Expand Down
5 changes: 5 additions & 0 deletions src/mongo_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,11 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
return this.s.bsonOptions;
}

/** @internal */
get timeoutMS(): number | undefined {
return this.options.timeoutMS;
}
Comment on lines +487 to +489
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to ensure that resolveOptions options inheritance is actually able to get option from MongoClient


/**
* Executes a client bulk write operation, available on server 8.0+.
* @param models - The client bulk write models.
Expand Down
1 change: 1 addition & 0 deletions src/operations/create_collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { Aspect, defineAspects } from './operation';
const ILLEGAL_COMMAND_FIELDS = new Set([
'w',
'wtimeout',
'timeoutMS',
Copy link
Contributor Author

@W-A-James W-A-James Sep 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added here as the benchmarks were adding the timeoutMS to the actual command being sent to the server when creating a collection, seems like it couldn't hurt to have this here.

'j',
'fsync',
'autoIndexId',
Expand Down
4 changes: 3 additions & 1 deletion test/benchmarks/driverBench/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ function loadSpecString(filePath) {
}

function makeClient() {
this.client = new MongoClient(process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017');
this.client = new MongoClient(process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017', {
timeoutMS: 0
});
}

function connectClient() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe('CSOT spec prose tests', function () {
beforeEach(async function () {
await internalClient
.db('db')
.collection('coll')
.collection('bulkWriteTest')
.drop()
.catch(() => null);
await internalClient.db('admin').command(failpoint);
Expand All @@ -93,7 +93,7 @@ describe('CSOT spec prose tests', function () {
const oneMBDocs = Array.from({ length: 50 }, (_, _id) => ({ _id, a }));
const error = await client
.db('db')
.collection<{ _id: number; a: Uint8Array }>('coll')
.collection<{ _id: number; a: Uint8Array }>('bulkWriteTest')
.insertMany(oneMBDocs)
.catch(error => error);

Expand Down Expand Up @@ -265,6 +265,7 @@ describe('CSOT spec prose tests', function () {
});

context('5. Blocking Iteration Methods', () => {
const metadata = { requires: { mongodb: '>=4.4' } };
/**
* Tests in this section MUST only be run against server versions 4.4 and higher and only apply to drivers that have a
* blocking method for cursor iteration that executes `getMore` commands in a loop until a document is available or an
Expand All @@ -276,7 +277,7 @@ describe('CSOT spec prose tests', function () {
data: {
failCommands: ['getMore'],
blockConnection: true,
blockTimeMS: 20
blockTimeMS: 90
}
};
let internalClient: MongoClient;
Expand All @@ -286,15 +287,25 @@ describe('CSOT spec prose tests', function () {

beforeEach(async function () {
internalClient = this.configuration.newClient();
await internalClient.db('db').dropCollection('coll');
await internalClient
.db('db')
.collection('coll')
.drop()
.catch(() => null);
// Creating capped collection to be able to create tailable find cursor
const coll = await internalClient
.db('db')
.createCollection('coll', { capped: true, size: 1_000_000 });
await coll.insertOne({ x: 1 });
await internalClient.db().admin().command(failpoint);

client = this.configuration.newClient(undefined, { timeoutMS: 20, monitorCommands: true });
client = this.configuration.newClient(undefined, {
monitorCommands: true,
timeoutMS: 100,
minPoolSize: 20
});
await client.connect();

commandStarted = [];
commandSucceeded = [];

Expand Down Expand Up @@ -337,11 +348,11 @@ describe('CSOT spec prose tests', function () {
* 1. Verify that a `find` command and two `getMore` commands were executed against the `db.coll` collection during the test.
*/

it.skip('send correct number of finds and getMores', async function () {
it('send correct number of finds and getMores', metadata, async function () {
const cursor = client
.db('db')
.collection('coll')
.find({}, { tailable: true, awaitData: true })
.find({}, { tailable: true })
.project({ _id: 0 });
const doc = await cursor.next();
expect(doc).to.deep.equal({ x: 1 });
Expand All @@ -358,7 +369,7 @@ describe('CSOT spec prose tests', function () {
expect(commandStarted.filter(e => e.command.find != null)).to.have.lengthOf(1);
// Expect 2 getMore
expect(commandStarted.filter(e => e.command.getMore != null)).to.have.lengthOf(2);
}).skipReason = 'TODO(NODE-6305)';
});
});

context('Change Streams', () => {
Expand All @@ -383,8 +394,11 @@ describe('CSOT spec prose tests', function () {
* - Expect this to fail with a timeout error.
* 1. Verify that an `aggregate` command and two `getMore` commands were executed against the `db.coll` collection during the test.
*/
it.skip('sends correct number of aggregate and getMores', async function () {
const changeStream = client.db('db').collection('coll').watch();
it.skip('sends correct number of aggregate and getMores', metadata, async function () {
const changeStream = client
.db('db')
.collection('coll')
.watch([], { timeoutMS: 20, maxAwaitTimeMS: 19 });
const maybeError = await changeStream.next().then(
() => null,
e => e
Expand All @@ -397,9 +411,9 @@ describe('CSOT spec prose tests', function () {
const getMores = commandStarted.filter(e => e.command.getMore != null).map(e => e.command);
// Expect 1 aggregate
expect(aggregates).to.have.lengthOf(1);
// Expect 1 getMore
expect(getMores).to.have.lengthOf(1);
}).skipReason = 'TODO(NODE-6305)';
// Expect 2 getMores
expect(getMores).to.have.lengthOf(2);
}).skipReason = 'TODO(NODE-6387)';
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ const skippedTests = {
'Non-tailable cursor lifetime remaining timeoutMS applied to getMore if timeoutMode is unset':
'TODO(DRIVERS-2965)',
'maxTimeMS value in the command is less than timeoutMS':
'TODO(DRIVERS-2970): see modified test in unified-csot-node-specs'
'TODO(DRIVERS-2970): see modified test in unified-csot-node-specs',
'Tailable cursor awaitData iteration timeoutMS is refreshed for getMore - failure':
'TODO(DRIVERS-2965)',
'Tailable cursor iteration timeoutMS is refreshed for getMore - failure': 'TODO(DRIVERS-2965)',
'timeoutMS is refreshed for getMore - failure':
'TODO(DRIVERS-2965): see modified test in unified-csot-node-specs' // Skipping for both tailable awaitData and tailable non-awaitData cursors
};

describe('CSOT spec tests', function () {
Expand Down
Loading