diff --git a/src/sessions.ts b/src/sessions.ts index f2b7d5281e..803a174dec 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -169,8 +169,10 @@ export class ClientSession extends TypedEventEmitter { this[kServerSession] = this.explicit ? this.sessionPool.acquire() : null; this[kTxnNumberIncrement] = 0; + const defaultCausalConsistencyValue = this.explicit && options.snapshot !== true; this.supports = { - causalConsistency: options.snapshot !== true && options.causalConsistency !== false + // if we can enable causal consistency, do so by default + causalConsistency: options.causalConsistency ?? defaultCausalConsistencyValue }; this.clusterTime = options.initialClusterTime; diff --git a/test/spec/sessions/implicit-sessions-default-causal-consistency.json b/test/spec/sessions/implicit-sessions-default-causal-consistency.json new file mode 100644 index 0000000000..517c8ebc63 --- /dev/null +++ b/test/spec/sessions/implicit-sessions-default-causal-consistency.json @@ -0,0 +1,318 @@ +{ + "description": "implicit sessions default causal consistency", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "topologies": [ + "replicaset", + "sharded", + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "implicit-cc-tests" + } + }, + { + "collection": { + "id": "collectionDefault", + "database": "database0", + "collectionName": "coll-default" + } + }, + { + "collection": { + "id": "collectionSnapshot", + "database": "database0", + "collectionName": "coll-snapshot", + "collectionOptions": { + "readConcern": { + "level": "snapshot" + } + } + } + }, + { + "collection": { + "id": "collectionlinearizable", + "database": "database0", + "collectionName": "coll-linearizable", + "collectionOptions": { + "readConcern": { + "level": "linearizable" + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll-default", + "databaseName": "implicit-cc-tests", + "documents": [ + { + "_id": 1, + "x": "default" + } + ] + }, + { + "collectionName": "coll-snapshot", + "databaseName": "implicit-cc-tests", + "documents": [ + { + "_id": 1, + "x": "snapshot" + } + ] + }, + { + "collectionName": "coll-linearizable", + "databaseName": "implicit-cc-tests", + "documents": [ + { + "_id": 1, + "x": "linearizable" + } + ] + } + ], + "tests": [ + { + "description": "readConcern is not sent on retried read in implicit session when readConcern level is not specified", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "find" + ], + "errorCode": 11600 + } + } + } + }, + { + "name": "find", + "object": "collectionDefault", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": 1, + "x": "default" + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll-default", + "filter": {}, + "readConcern": { + "$$exists": false + } + }, + "databaseName": "implicit-cc-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "coll-default", + "filter": {}, + "readConcern": { + "$$exists": false + } + }, + "databaseName": "implicit-cc-tests" + } + } + ] + } + ] + }, + { + "description": "afterClusterTime is not sent on retried read in implicit session when readConcern level is snapshot", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "find" + ], + "errorCode": 11600 + } + } + } + }, + { + "name": "find", + "object": "collectionSnapshot", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": 1, + "x": "snapshot" + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll-snapshot", + "filter": {}, + "readConcern": { + "level": "snapshot", + "afterClusterTime": { + "$$exists": false + } + } + }, + "databaseName": "implicit-cc-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "coll-snapshot", + "filter": {}, + "readConcern": { + "level": "snapshot", + "afterClusterTime": { + "$$exists": false + } + } + }, + "databaseName": "implicit-cc-tests" + } + } + ] + } + ] + }, + { + "description": "afterClusterTime is not sent on retried read in implicit session when readConcern level is linearizable", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "find" + ], + "errorCode": 11600 + } + } + } + }, + { + "name": "find", + "object": "collectionlinearizable", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": 1, + "x": "linearizable" + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll-linearizable", + "filter": {}, + "readConcern": { + "level": "linearizable", + "afterClusterTime": { + "$$exists": false + } + } + }, + "databaseName": "implicit-cc-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "coll-linearizable", + "filter": {}, + "readConcern": { + "level": "linearizable", + "afterClusterTime": { + "$$exists": false + } + } + }, + "databaseName": "implicit-cc-tests" + } + } + ] + } + ] + } + ] +} diff --git a/test/spec/sessions/implicit-sessions-default-causal-consistency.yml b/test/spec/sessions/implicit-sessions-default-causal-consistency.yml new file mode 100644 index 0000000000..052c6dac20 --- /dev/null +++ b/test/spec/sessions/implicit-sessions-default-causal-consistency.yml @@ -0,0 +1,119 @@ +description: "implicit sessions default causal consistency" + +schemaVersion: "1.3" + +runOnRequirements: + - minServerVersion: "4.2" + topologies: [replicaset, sharded, load-balanced] + +createEntities: + - client: + id: &client0 client0 + useMultipleMongoses: false + observeEvents: [commandStartedEvent] + - database: + id: &database0 database0 + client: *client0 + databaseName: &databaseName implicit-cc-tests + - collection: + id: &collectionDefault collectionDefault + database: *database0 + collectionName: &collectionNameDefault coll-default + - collection: + id: &collectionSnapshot collectionSnapshot + database: *database0 + collectionName: &collectionNameSnapshot coll-snapshot + collectionOptions: + readConcern: { level: snapshot } + - collection: + id: &collectionlinearizable collectionlinearizable + database: *database0 + collectionName: &collectionNamelinearizable coll-linearizable + collectionOptions: + readConcern: { level: linearizable } + +initialData: + - collectionName: *collectionNameDefault + databaseName: *databaseName + documents: + - { _id: 1, x: default } + - collectionName: *collectionNameSnapshot + databaseName: *databaseName + documents: + - { _id: 1, x: snapshot } + - collectionName: *collectionNamelinearizable + databaseName: *databaseName + documents: + - { _id: 1, x: linearizable } + +tests: + - description: "readConcern is not sent on retried read in implicit session when readConcern level is not specified" + operations: + - &failPointCommand + name: failPoint + object: testRunner + arguments: + client: *client0 + failPoint: + configureFailPoint: failCommand + mode: { times: 1 } + data: + failCommands: [find] + errorCode: 11600 #InterruptedAtShutdown + - name: find + object: *collectionDefault + arguments: + filter: {} + expectResult: [{ _id: 1, x: default }] + expectEvents: + - client: *client0 + events: + - commandStartedEvent: &commandStartedEventDefault + command: + find: *collectionNameDefault + filter: {} + readConcern: { $$exists: false } + databaseName: *databaseName + - commandStartedEvent: *commandStartedEventDefault + + - description: "afterClusterTime is not sent on retried read in implicit session when readConcern level is snapshot" + runOnRequirements: + - minServerVersion: "5.0" + operations: + - *failPointCommand + - name: find + object: *collectionSnapshot + arguments: + filter: {} + expectResult: [{ _id: 1, x: snapshot }] + expectEvents: + - client: *client0 + events: + - commandStartedEvent: &commandStartedEventSnapshot + command: + find: *collectionNameSnapshot + filter: {} + readConcern: + { level: snapshot, afterClusterTime: { $$exists: false } } + databaseName: *databaseName + - commandStartedEvent: *commandStartedEventSnapshot + + - description: "afterClusterTime is not sent on retried read in implicit session when readConcern level is linearizable" + operations: + - *failPointCommand + - name: find + object: *collectionlinearizable + arguments: + filter: {} + expectResult: [{ _id: 1, x: linearizable }] + expectEvents: + - client: *client0 + events: + - commandStartedEvent: &commandStartedEventLinearizable + command: + find: *collectionNamelinearizable + filter: {} + readConcern: + { level: linearizable, afterClusterTime: { $$exists: false } } + databaseName: *databaseName + - commandStartedEvent: *commandStartedEventLinearizable diff --git a/test/unit/sessions.test.js b/test/unit/sessions.test.js index fd75f22812..b357a239c3 100644 --- a/test/unit/sessions.test.js +++ b/test/unit/sessions.test.js @@ -167,6 +167,65 @@ describe('Sessions - unit', function () { ).to.throw('Properties "causalConsistency" and "snapshot" are mutually exclusive'); }); + it('should default `causalConsistency` to `true` for explicit non-snapshot sessions', function () { + const session = new ClientSession(client, serverSessionPool, { explicit: true }); + expect(session.supports).property('causalConsistency', true); + }); + + it('should default `causalConsistency` to `false` for explicit snapshot sessions', function () { + const session = new ClientSession(client, serverSessionPool, { + explicit: true, + snapshot: true + }); + expect(session.supports).property('causalConsistency', false); + }); + + it('should allow `causalConsistency=false` option in explicit snapshot sessions', function () { + const session = new ClientSession(client, serverSessionPool, { + explicit: true, + causalConsistency: false, + snapshot: true + }); + expect(session.supports).property('causalConsistency', false); + }); + + it('should respect `causalConsistency=false` option in explicit sessions', function () { + const session = new ClientSession(client, serverSessionPool, { + explicit: true, + causalConsistency: false + }); + expect(session.supports).property('causalConsistency', false); + }); + + it('should respect `causalConsistency=true` option in explicit non-snapshot sessions', function () { + const session = new ClientSession(client, serverSessionPool, { + explicit: true, + causalConsistency: true + }); + expect(session.supports).property('causalConsistency', true); + }); + + it('should default `causalConsistency` to `false` for implicit sessions', function () { + const session = new ClientSession(client, serverSessionPool, { explicit: false }); + expect(session.supports).property('causalConsistency', false); + }); + + it('should respect `causalConsistency=false` option in implicit sessions', function () { + const session = new ClientSession(client, serverSessionPool, { + explicit: false, + causalConsistency: false + }); + expect(session.supports).property('causalConsistency', false); + }); + + it('should respect `causalConsistency=true` option in implicit sessions', function () { + const session = new ClientSession(client, serverSessionPool, { + explicit: false, + causalConsistency: true + }); + expect(session.supports).property('causalConsistency', true); + }); + it('should default to `null` for `clusterTime`', function () { const session = new ClientSession(client, serverSessionPool); expect(session.clusterTime).to.not.exist;