description: transactions are correctly pinned to connections for load-balanced clusters schemaVersion: '1.3' runOnRequirements: - topologies: [ load-balanced ] createEntities: - client: id: &client0 client0 useMultipleMongoses: true observeEvents: # Do not observe commandSucceededEvent or commandFailedEvent because we cannot guarantee success or failure of # commands like commitTransaction and abortTransaction in a multi-mongos load-balanced setup. - commandStartedEvent - connectionReadyEvent - connectionClosedEvent - connectionCheckedOutEvent - connectionCheckedInEvent - session: id: &session0 session0 client: *client0 - database: id: &database0 database0 client: *client0 databaseName: &database0Name database0Name - collection: id: &collection0 collection0 database: *database0 collectionName: &collection0Name coll0 initialData: - collectionName: *collection0Name databaseName: *database0Name documents: - { _id: 1 } - { _id: 2 } - { _id: 3 } _yamlAnchors: documents: - &insertDocument _id: 4 tests: - description: sessions are reused in LB mode operations: - &nonTransactionalInsert name: insertOne object: *collection0 arguments: document: { x: 1 } - *nonTransactionalInsert - name: assertSameLsidOnLastTwoCommands object: testRunner arguments: client: *client0 - description: all operations go to the same mongos operations: - &startTransaction name: startTransaction object: *session0 - &transactionalInsert name: insertOne object: *collection0 arguments: document: { x: 1 } session: *session0 - &assertConnectionPinned name: assertNumberConnectionsCheckedOut object: testRunner arguments: client: *client0 connections: 1 - *transactionalInsert - *transactionalInsert - *transactionalInsert - *transactionalInsert - *transactionalInsert - *assertConnectionPinned - &commitTransaction name: commitTransaction object: *session0 expectEvents: - client: *client0 events: - &insertStarted commandStartedEvent: commandName: insert - *insertStarted - *insertStarted - *insertStarted - *insertStarted - *insertStarted - &commitStarted commandStartedEvent: commandName: commitTransaction - client: *client0 eventType: cmap events: # The connection is never checked back in. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - description: transaction can be committed multiple times operations: - *startTransaction - *transactionalInsert - *assertConnectionPinned - *commitTransaction - *assertConnectionPinned - *commitTransaction - *commitTransaction - *commitTransaction - *assertConnectionPinned expectEvents: - client: *client0 events: - *insertStarted - *commitStarted - *commitStarted - *commitStarted - *commitStarted - client: *client0 eventType: cmap events: - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - description: pinned connection is not released after a non-transient CRUD error operations: - name: failPoint object: testRunner arguments: client: *client0 failPoint: configureFailPoint: failCommand mode: { times: 1 } data: failCommands: [ insert ] errorCode: &nonTransientErrorCode 51 # ManualInterventionRequired - *startTransaction - name: insertOne object: *collection0 arguments: document: { x: 1 } session: *session0 expectError: &nonTransientExpectedError errorCode: *nonTransientErrorCode errorLabelsOmit: [ TransientTransactionError ] - *assertConnectionPinned expectEvents: - client: *client0 events: - *insertStarted - client: *client0 eventType: cmap events: # Events for setting the fail point. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} # Events for the transactional insert. - connectionCheckedOutEvent: {} - description: pinned connection is not released after a non-transient commit error operations: - name: failPoint object: testRunner arguments: client: *client0 failPoint: configureFailPoint: failCommand mode: { times: 1 } data: failCommands: [ commitTransaction ] errorCode: *nonTransientErrorCode - *startTransaction - *transactionalInsert - name: commitTransaction object: *session0 expectError: *nonTransientExpectedError - *assertConnectionPinned expectEvents: - client: *client0 events: - *insertStarted - *commitStarted - client: *client0 eventType: cmap events: # Events for setting the fail point. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} # Events for the transactional insert and commit. - connectionCheckedOutEvent: {} # Errors during abort are different than errors during commit and CRUD operations because the pinned connection is # always released after abort. - description: pinned connection is released after a non-transient abort error operations: - name: failPoint object: testRunner arguments: client: *client0 failPoint: configureFailPoint: failCommand mode: { times: 1 } data: failCommands: [ abortTransaction ] errorCode: &nonTransientErrorCode 51 # ManualInterventionRequired - *startTransaction - *transactionalInsert - name: abortTransaction object: *session0 - &assertConnectionNotPinned name: assertNumberConnectionsCheckedOut object: testRunner arguments: client: *client0 connections: 0 expectEvents: - client: *client0 events: - *insertStarted - &abortStarted commandStartedEvent: commandName: abortTransaction - client: *client0 eventType: cmap events: # Events for setting the fail point. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} # Events for the transactional insert and abort. - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} - description: pinned connection is released after a transient non-network CRUD error runOnRequirements: - serverless: forbid # (CLOUDP-88216) Serverless does not append error labels to errors triggered by failpoints. operations: - name: failPoint object: testRunner arguments: client: *client0 failPoint: configureFailPoint: failCommand mode: { times: 1 } data: failCommands: [ insert ] errorCode: &transientErrorCode 24 # LockTimeout - *startTransaction - <<: *transactionalInsert expectError: &transientExpectedServerError errorCode: *transientErrorCode errorLabelsContain: [ TransientTransactionError ] - *assertConnectionNotPinned - name: abortTransaction object: *session0 - *assertConnectionNotPinned expectEvents: - client: *client0 events: - *insertStarted - *abortStarted - client: *client0 eventType: cmap events: # Events for setting the failpoint. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} # Events for the insert. - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} # Events for abortTransction. - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} - description: pinned connection is released after a transient network CRUD error runOnRequirements: - serverless: forbid # (CLOUDP-88216) Serverless does not append error labels to errors triggered by failpoints. operations: - name: failPoint object: testRunner arguments: client: *client0 failPoint: configureFailPoint: failCommand mode: { times: 1 } data: failCommands: [ insert ] closeConnection: true - *startTransaction - <<: *transactionalInsert expectError: &transientExpectedNetworkError isClientError: true errorLabelsContain: [ TransientTransactionError ] - *assertConnectionNotPinned - name: abortTransaction object: *session0 - *assertConnectionNotPinned expectEvents: - client: *client0 events: - *insertStarted - *abortStarted - client: *client0 eventType: cmap events: # Events for setting the failpoint. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} # Events for the insert. - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} - connectionClosedEvent: reason: error # Events for abortTransaction - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} - description: pinned connection is released after a transient non-network commit error runOnRequirements: - serverless: forbid # (CLOUDP-88216) Serverless does not append error labels to errors triggered by failpoints. operations: - name: failPoint object: testRunner arguments: client: *client0 failPoint: configureFailPoint: failCommand mode: { times: 1 } data: failCommands: [ commitTransaction ] errorCode: *transientErrorCode - *startTransaction - *transactionalInsert - <<: *commitTransaction expectError: *transientExpectedServerError - *assertConnectionNotPinned expectEvents: - client: *client0 events: - *insertStarted - *commitStarted - client: *client0 eventType: cmap events: # Events for setting the failpoint. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} # Events for the insert. - connectionCheckedOutEvent: {} # Events for commitTransaction. - connectionCheckedInEvent: {} - description: pinned connection is released after a transient network commit error operations: - name: failPoint object: testRunner arguments: client: *client0 failPoint: configureFailPoint: failCommand mode: { times: 1 } data: failCommands: [ commitTransaction ] closeConnection: true - *startTransaction - *transactionalInsert - <<: *commitTransaction # Ignore the result and error because the operation might fail if it targets a new mongos that isn't aware of # the transaction or the server-side reaper thread closes the transaction first. We only want to assert that # the operation is retried, which is done via monitoring expectations, so the exact result/error is not # necessary. ignoreResultAndError: true - *assertConnectionNotPinned expectEvents: - client: *client0 events: - *insertStarted - *commitStarted # The commit will be automatically retried. - *commitStarted - client: *client0 eventType: cmap events: # Events for setting the failpoint. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} # Events for the insert. - connectionCheckedOutEvent: {} # Events for the first commitTransaction. - connectionCheckedInEvent: {} - connectionClosedEvent: reason: error # Events for the commitTransaction retry. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} - description: pinned connection is released after a transient non-network abort error operations: - name: failPoint object: testRunner arguments: client: *client0 failPoint: configureFailPoint: failCommand mode: { times: 1 } data: failCommands: [ abortTransaction ] errorCode: *transientErrorCode - *startTransaction - *transactionalInsert - name: abortTransaction object: *session0 - *assertConnectionNotPinned expectEvents: - client: *client0 events: - *insertStarted - *abortStarted - client: *client0 eventType: cmap events: # Events for setting the failpoint. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} # Events for the insert. - connectionCheckedOutEvent: {} # Events for abortTransaction. - connectionCheckedInEvent: {} - description: pinned connection is released after a transient network abort error operations: - name: failPoint object: testRunner arguments: client: *client0 failPoint: configureFailPoint: failCommand mode: { times: 1 } data: failCommands: [ abortTransaction ] closeConnection: true - *startTransaction - *transactionalInsert - name: abortTransaction object: *session0 - *assertConnectionNotPinned expectEvents: - client: *client0 events: - *insertStarted - *abortStarted # The abort will be automatically retried. - *abortStarted - client: *client0 eventType: cmap events: # Events for setting the failpoint. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} # Events for the insert. - connectionCheckedOutEvent: {} # Events for the first abortTransaction. - connectionCheckedInEvent: {} - connectionClosedEvent: reason: error # Events for the abortTransaction retry. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} - description: pinned connection is released on successful abort operations: - *startTransaction - *transactionalInsert - name: abortTransaction object: *session0 - *assertConnectionNotPinned expectEvents: - client: *client0 events: - *insertStarted - *abortStarted - client: *client0 eventType: cmap events: # The insert will create and pin a connection. The abort will use it and then unpin. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} - description: pinned connection is returned when a new transaction is started operations: - *startTransaction - *transactionalInsert - *commitTransaction - *assertConnectionPinned - *startTransaction - *assertConnectionNotPinned # startTransaction will unpin the connection. - *transactionalInsert - *assertConnectionPinned # The first operation in the new transaction will pin the connection again. - *commitTransaction expectEvents: - client: *client0 events: - *insertStarted - *commitStarted - *insertStarted - *commitStarted - client: *client0 eventType: cmap events: # Events for the first insert and commit. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} # Events for startTransaction. - connectionCheckedInEvent: {} # Events for the second insert and commit. - connectionCheckedOutEvent: {} - description: pinned connection is returned when a non-transaction operation uses the session operations: - *startTransaction - *transactionalInsert - *commitTransaction - *assertConnectionPinned - *transactionalInsert # The insert is a non-transactional operation that uses the session, so it unpins the connection. - *assertConnectionNotPinned expectEvents: - client: *client0 events: - *insertStarted - *commitStarted - *insertStarted - client: *client0 eventType: cmap events: # Events for the first insert and commit. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} # Events for the second insert. - connectionCheckedInEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} - description: a connection can be shared by a transaction and a cursor operations: - *startTransaction - *transactionalInsert - *assertConnectionPinned - name: createFindCursor object: *collection0 arguments: filter: {} batchSize: 2 session: *session0 saveResultAsEntity: &cursor0 cursor0 - *assertConnectionPinned - name: close object: *cursor0 - *assertConnectionPinned # Abort the transaction to ensure that the connection is unpinned. - name: abortTransaction object: *session0 - *assertConnectionNotPinned expectEvents: - client: *client0 events: - *insertStarted - commandStartedEvent: commandName: find - commandStartedEvent: commandName: killCursors - *abortStarted - client: *client0 eventType: cmap events: # Events for the insert, find, and killCursors. - connectionReadyEvent: {} - connectionCheckedOutEvent: {} # Events for abortTransaction. - connectionCheckedInEvent: {}