diff --git a/pymongo/client_session.py b/pymongo/client_session.py index 63021a3c0..7c5db5a42 100644 --- a/pymongo/client_session.py +++ b/pymongo/client_session.py @@ -98,13 +98,11 @@ Classes """ import collections -import os -import sys import uuid from bson.binary import Binary from bson.int64 import Int64 -from bson.py3compat import abc, integer_types, reraise_instance +from bson.py3compat import abc, integer_types from bson.son import SON from bson.timestamp import Timestamp @@ -114,7 +112,6 @@ from pymongo.errors import (ConfigurationError, InvalidOperation, OperationFailure, PyMongoError, - ServerSelectionTimeoutError, WTimeoutError) from pymongo.helpers import _RETRYABLE_ERROR_CODES from pymongo.read_concern import ReadConcern @@ -295,6 +292,7 @@ class _Transaction(object): self.sharded = False self.pinned_address = None self.recovery_token = None + self.attempt = 0 def active(self): return self.state in (_TxnState.STARTING, _TxnState.IN_PROGRESS) @@ -304,12 +302,13 @@ class _Transaction(object): self.sharded = False self.pinned_address = None self.recovery_token = None + self.attempt = 0 def _reraise_with_unknown_commit(exc): """Re-raise an exception with the UnknownTransactionCommitResult label.""" exc._add_error_label("UnknownTransactionCommitResult") - reraise_instance(exc, trace=sys.exc_info()[2]) + raise def _max_time_expired_error(exc): @@ -579,7 +578,6 @@ class ClientSession(object): .. versionadded:: 3.7 """ self._check_ended() - retry = False state = self._transaction.state if state is _TxnState.NONE: raise InvalidOperation("No transaction started") @@ -594,10 +592,9 @@ class ClientSession(object): # We're explicitly retrying the commit, move the state back to # "in progress" so that in_transaction returns true. self._transaction.state = _TxnState.IN_PROGRESS - retry = True try: - self._finish_transaction_with_retry("commitTransaction", retry) + self._finish_transaction_with_retry("commitTransaction") except ConnectionFailure as exc: # We do not know if the commit was successfully applied on the # server or if it satisfied the provided write concern, set the @@ -640,44 +637,25 @@ class ClientSession(object): "Cannot call abortTransaction after calling commitTransaction") try: - self._finish_transaction_with_retry("abortTransaction", False) + self._finish_transaction_with_retry("abortTransaction") except (OperationFailure, ConnectionFailure): # The transactions spec says to ignore abortTransaction errors. pass finally: self._transaction.state = _TxnState.ABORTED - def _finish_transaction_with_retry(self, command_name, explict_retry): + def _finish_transaction_with_retry(self, command_name): """Run commit or abort with one retry after any retryable error. :Parameters: - `command_name`: Either "commitTransaction" or "abortTransaction". - - `explict_retry`: True when this is an explict commit retry attempt, - ie the application called session.commit_transaction() twice. """ - # This can be refactored with MongoClient._retry_with_session. - try: - return self._finish_transaction(command_name, explict_retry) - except ServerSelectionTimeoutError: - raise - except ConnectionFailure as exc: - try: - return self._finish_transaction(command_name, True) - except ServerSelectionTimeoutError: - # Raise the original error so the application can infer that - # an attempt was made. - raise exc - except OperationFailure as exc: - if exc.code not in _RETRYABLE_ERROR_CODES: - raise - try: - return self._finish_transaction(command_name, True) - except ServerSelectionTimeoutError: - # Raise the original error so the application can infer that - # an attempt was made. - raise exc + def func(session, sock_info, retryable): + return self._finish_transaction(sock_info, command_name) + return self._client._retry_internal(True, func, self, None) - def _finish_transaction(self, command_name, retrying): + def _finish_transaction(self, sock_info, command_name): + self._transaction.attempt += 1 opts = self._transaction.opts wc = opts.write_concern cmd = SON([(command_name, 1)]) @@ -688,7 +666,7 @@ class ClientSession(object): # Transaction spec says that after the initial commit attempt, # subsequent commitTransaction commands should be upgraded to use # w:"majority" and set a default value of 10 seconds for wtimeout. - if retrying: + if self._transaction.attempt > 1: wc_doc = wc.document wc_doc["w"] = "majority" wc_doc.setdefault("wtimeout", 10000) @@ -697,13 +675,12 @@ class ClientSession(object): if self._transaction.recovery_token: cmd['recoveryToken'] = self._transaction.recovery_token - with self._client._socket_for_writes(self) as sock_info: - return self._client.admin._command( - sock_info, - cmd, - session=self, - write_concern=wc, - parse_write_concern_error=True) + return self._client.admin._command( + sock_info, + cmd, + session=self, + write_concern=wc, + parse_write_concern_error=True) def _advance_cluster_time(self, cluster_time): """Internal cluster time helper.""" diff --git a/pymongo/errors.py b/pymongo/errors.py index fb4b45628..c11053f47 100644 --- a/pymongo/errors.py +++ b/pymongo/errors.py @@ -48,7 +48,7 @@ class PyMongoError(Exception): def _remove_error_label(self, label): """Remove the given label from this error.""" - self._error_labels.remove(label) + self._error_labels.discard(label) if sys.version_info[0] == 2: def __str__(self): @@ -68,12 +68,6 @@ class ProtocolError(PyMongoError): class ConnectionFailure(PyMongoError): """Raised when a connection to the database cannot be made or is lost.""" - def __init__(self, message='', error_labels=None): - if error_labels is None: - # Connection errors are transient errors by default. - error_labels = ("TransientTransactionError",) - super(ConnectionFailure, self).__init__( - message, error_labels=error_labels) class AutoReconnect(ConnectionFailure): @@ -89,7 +83,10 @@ class AutoReconnect(ConnectionFailure): Subclass of :exc:`~pymongo.errors.ConnectionFailure`. """ def __init__(self, message='', errors=None): - super(AutoReconnect, self).__init__(message) + error_labels = None + if errors is not None and isinstance(errors, dict): + error_labels = errors.get('errorLabels') + super(AutoReconnect, self).__init__(message, error_labels) self.errors = self.details = errors or [] diff --git a/pymongo/mongo_client.py b/pymongo/mongo_client.py index 7b84e2e50..0c93604a3 100644 --- a/pymongo/mongo_client.py +++ b/pymongo/mongo_client.py @@ -59,6 +59,7 @@ from pymongo.errors import (AutoReconnect, ConfigurationError, ConnectionFailure, InvalidOperation, + NotMasterError, OperationFailure, PyMongoError, ServerSelectionTimeoutError) @@ -1265,7 +1266,9 @@ class MongoClient(common.BaseObject): session._pin_mongos(server) return server except PyMongoError as exc: - if session and exc.has_error_label("TransientTransactionError"): + # Server selection errors in a transaction are transient. + if session and session.in_transaction: + exc._add_error_label("TransientTransactionError") session._unpin_mongos() raise @@ -1361,6 +1364,11 @@ class MongoClient(common.BaseObject): """ retryable = (retryable and self.retry_writes and session and not session.in_transaction) + return self._retry_internal(retryable, func, session, bulk) + + def _retry_internal(self, retryable, func, session, bulk): + """Internal retryable write helper.""" + max_wire_version = 0 last_error = None retrying = False @@ -1369,7 +1377,7 @@ class MongoClient(common.BaseObject): # Increment the transaction id up front to ensure any retry attempt # will use the proper txnNumber, even if server or socket selection # fails before the command can be sent. - if retryable: + if retryable and session and not session.in_transaction: session._start_retryable_write() if bulk: bulk.started_retryable_write = True @@ -1381,6 +1389,7 @@ class MongoClient(common.BaseObject): session is not None and server.description.retryable_writes_supported) with self._get_socket(server, session) as sock_info: + max_wire_version = sock_info.max_wire_version if retryable and not supports_session: if is_retrying(): # A retry is not possible because this server does @@ -1398,40 +1407,12 @@ class MongoClient(common.BaseObject): # be a persistent outage. Attempting to retry in this case will # most likely be a waste of time. raise - except ConnectionFailure as exc: - if not retryable or is_retrying(): + except Exception as exc: + if not retryable: raise - if bulk: - bulk.retrying = True - else: - retrying = True - last_error = exc - except BulkWriteError as exc: - if not retryable or is_retrying(): - raise - # Check the last writeConcernError to determine if this - # BulkWriteError is retryable. - wces = exc.details['writeConcernErrors'] - wce = wces[-1] if wces else {} - if wce.get('code', 0) not in helpers._RETRYABLE_ERROR_CODES: - raise - if bulk: - bulk.retrying = True - else: - retrying = True - last_error = exc - except OperationFailure as exc: - # retryWrites on MMAPv1 should raise an actionable error. - if (exc.code == 20 and - str(exc).startswith("Transaction numbers")): - errmsg = ( - "This MongoDB deployment does not support " - "retryable writes. Please add retryWrites=false " - "to your connection string.") - raise OperationFailure(errmsg, exc.code, exc.details) - if not retryable or is_retrying(): - raise - if exc.code not in helpers._RETRYABLE_ERROR_CODES: + # Add the RetryableWriteError label. + if (not _retryable_writes_error(exc, max_wire_version) + or is_retrying()): raise if bulk: bulk.retrying = True @@ -2162,26 +2143,66 @@ class MongoClient(common.BaseObject): next = __next__ +def _retryable_error_doc(exc): + """Return the server response from PyMongo exception or None.""" + if isinstance(exc, BulkWriteError): + # Check the last writeConcernError to determine if this + # BulkWriteError is retryable. + wces = exc.details['writeConcernErrors'] + wce = wces[-1] if wces else None + return wce + if isinstance(exc, (NotMasterError, OperationFailure)): + return exc.details + return None + + +def _retryable_writes_error(exc, max_wire_version): + doc = _retryable_error_doc(exc) + if doc: + code = doc.get('code', 0) + # retryWrites on MMAPv1 should raise an actionable error. + if (code == 20 and + str(exc).startswith("Transaction numbers")): + errmsg = ( + "This MongoDB deployment does not support " + "retryable writes. Please add retryWrites=false " + "to your connection string.") + raise OperationFailure(errmsg, code, exc.details) + if max_wire_version >= 9: + # MongoDB 4.4+ utilizes RetryableWriteError. + return 'RetryableWriteError' in doc.get('errorLabels', []) + else: + if code in helpers._RETRYABLE_ERROR_CODES: + exc._add_error_label("RetryableWriteError") + return True + return False + + if isinstance(exc, ConnectionFailure): + exc._add_error_label("RetryableWriteError") + return True + return False + + class _MongoClientErrorHandler(object): - """Error handler for MongoClient.""" - __slots__ = ('_client', '_server_address', '_session', - '_max_wire_version', '_sock_generation') + """Handle errors raised when executing an operation.""" + __slots__ = ('client', 'server_address', 'session', 'max_wire_version', + 'sock_generation') def __init__(self, client, server, session): - self._client = client - self._server_address = server.description.address - self._session = session - self._max_wire_version = common.MIN_WIRE_VERSION + self.client = client + self.server_address = server.description.address + self.session = session + self.max_wire_version = common.MIN_WIRE_VERSION # XXX: When get_socket fails, this generation could be out of date: # "Note that when a network error occurs before the handshake # completes then the error's generation number is the generation # of the pool at the time the connection attempt was started." - self._sock_generation = server.pool.generation + self.sock_generation = server.pool.generation def contribute_socket(self, sock_info): """Provide socket information to the error handler.""" - self._max_wire_version = sock_info.max_wire_version - self._sock_generation = sock_info.generation + self.max_wire_version = sock_info.max_wire_version + self.sock_generation = sock_info.generation def __enter__(self): return self @@ -2190,15 +2211,16 @@ class _MongoClientErrorHandler(object): if exc_type is None: return + if self.session: + if issubclass(exc_type, ConnectionFailure): + if self.session.in_transaction: + exc_val._add_error_label("TransientTransactionError") + self.session._server_session.mark_dirty() + + if issubclass(exc_type, PyMongoError): + if exc_val.has_error_label("TransientTransactionError"): + self.session._unpin_mongos() + err_ctx = _ErrorContext( - exc_val, self._max_wire_version, self._sock_generation) - self._client._topology.handle_error(self._server_address, err_ctx) - - if issubclass(exc_type, PyMongoError): - if self._session and exc_val.has_error_label( - "TransientTransactionError"): - self._session._unpin_mongos() - - if issubclass(exc_type, ConnectionFailure): - if self._session: - self._session._server_session.mark_dirty() + exc_val, self.max_wire_version, self.sock_generation) + self.client._topology.handle_error(self.server_address, err_ctx) diff --git a/test/retryable_writes/bulkWrite-errorLabels.json b/test/retryable_writes/bulkWrite-errorLabels.json new file mode 100644 index 000000000..94ea3ea98 --- /dev/null +++ b/test/retryable_writes/bulkWrite-errorLabels.json @@ -0,0 +1,182 @@ +{ + "runOn": [ + { + "minServerVersion": "4.3.1", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "tests": [ + { + "description": "BulkWrite succeeds with RetryableWriteError from server", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "update" + ], + "errorCode": 112, + "errorLabels": [ + "RetryableWriteError" + ] + } + }, + "operation": { + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + } + } + }, + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 3, + "x": 33 + } + } + }, + { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + } + ], + "options": { + "ordered": true + } + } + }, + "outcome": { + "result": { + "deletedCount": 1, + "insertedCount": 1, + "insertedIds": { + "1": 3 + }, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + }, + "collection": { + "data": [ + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "BulkWrite fails if server does not return RetryableWriteError", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "update" + ], + "errorCode": 11600, + "errorLabels": [] + } + }, + "operation": { + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + } + } + }, + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 3, + "x": 33 + } + } + }, + { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + } + ], + "options": { + "ordered": true + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + } + ] +} diff --git a/test/retryable_writes/bulkWrite-serverErrors.json b/test/retryable_writes/bulkWrite-serverErrors.json index 79c81a583..d9561d568 100644 --- a/test/retryable_writes/bulkWrite-serverErrors.json +++ b/test/retryable_writes/bulkWrite-serverErrors.json @@ -35,7 +35,10 @@ "failCommands": [ "update" ], - "errorCode": 189 + "errorCode": 189, + "errorLabels": [ + "RetryableWriteError" + ] } }, "operation": { @@ -117,7 +120,10 @@ ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -186,6 +192,81 @@ ] } } + }, + { + "description": "BulkWrite fails with a RetryableWriteError label after two connection failures", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "update" + ], + "closeConnection": true + } + }, + "operation": { + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + } + } + }, + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 3, + "x": 33 + } + } + }, + { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + } + ], + "options": { + "ordered": true + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsContain": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } } ] } diff --git a/test/retryable_writes/deleteOne-errorLabels.json b/test/retryable_writes/deleteOne-errorLabels.json new file mode 100644 index 000000000..bff02e1f9 --- /dev/null +++ b/test/retryable_writes/deleteOne-errorLabels.json @@ -0,0 +1,106 @@ +{ + "runOn": [ + { + "minServerVersion": "4.3.1", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "tests": [ + { + "description": "DeleteOne succeeds with RetryableWriteError from server", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "delete" + ], + "errorCode": 112, + "errorLabels": [ + "RetryableWriteError" + ] + } + }, + "operation": { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + } + } + }, + "outcome": { + "result": { + "deletedCount": 1 + }, + "collection": { + "data": [ + { + "_id": 2, + "x": 22 + } + ] + } + } + }, + { + "description": "DeleteOne fails if server does not return RetryableWriteError", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "delete" + ], + "errorCode": 11600, + "errorLabels": [] + } + }, + "operation": { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + } + ] +} diff --git a/test/retryable_writes/deleteOne-serverErrors.json b/test/retryable_writes/deleteOne-serverErrors.json index 9ef2bf2f2..69d225759 100644 --- a/test/retryable_writes/deleteOne-serverErrors.json +++ b/test/retryable_writes/deleteOne-serverErrors.json @@ -35,7 +35,10 @@ "failCommands": [ "delete" ], - "errorCode": 189 + "errorCode": 189, + "errorLabels": [ + "RetryableWriteError" + ] } }, "operation": { @@ -73,7 +76,10 @@ ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -98,6 +104,49 @@ ] } } + }, + { + "description": "DeleteOne fails with RetryableWriteError label after two connection failures", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "delete" + ], + "closeConnection": true + } + }, + "operation": { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsContain": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } } ] } diff --git a/test/retryable_writes/findOneAndDelete-errorLabels.json b/test/retryable_writes/findOneAndDelete-errorLabels.json new file mode 100644 index 000000000..efa62dba2 --- /dev/null +++ b/test/retryable_writes/findOneAndDelete-errorLabels.json @@ -0,0 +1,117 @@ +{ + "runOn": [ + { + "minServerVersion": "4.3.1", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "tests": [ + { + "description": "FindOneAndDelete succeeds with RetryableWriteError from server", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "errorCode": 112, + "errorLabels": [ + "RetryableWriteError" + ] + } + }, + "operation": { + "name": "findOneAndDelete", + "arguments": { + "filter": { + "x": { + "$gte": 11 + } + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "_id": 1, + "x": 11 + }, + "collection": { + "data": [ + { + "_id": 2, + "x": 22 + } + ] + } + } + }, + { + "description": "FindOneAndDelete fails if server does not return RetryableWriteError", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "errorCode": 11600, + "errorLabels": [] + } + }, + "operation": { + "name": "findOneAndDelete", + "arguments": { + "filter": { + "x": { + "$gte": 11 + } + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + } + ] +} diff --git a/test/retryable_writes/findOneAndDelete-serverErrors.json b/test/retryable_writes/findOneAndDelete-serverErrors.json index d72d1a05b..0785e5d03 100644 --- a/test/retryable_writes/findOneAndDelete-serverErrors.json +++ b/test/retryable_writes/findOneAndDelete-serverErrors.json @@ -35,7 +35,10 @@ "failCommands": [ "findAndModify" ], - "errorCode": 189 + "errorCode": 189, + "errorLabels": [ + "RetryableWriteError" + ] } }, "operation": { @@ -79,7 +82,10 @@ ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -110,6 +116,54 @@ ] } } + }, + { + "description": "FindOneAndDelete fails with a RetryableWriteError label after two connection failures", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "closeConnection": true + } + }, + "operation": { + "name": "findOneAndDelete", + "arguments": { + "filter": { + "x": { + "$gte": 11 + } + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsContain": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } } ] } diff --git a/test/retryable_writes/findOneAndReplace-errorLabels.json b/test/retryable_writes/findOneAndReplace-errorLabels.json new file mode 100644 index 000000000..d9473d139 --- /dev/null +++ b/test/retryable_writes/findOneAndReplace-errorLabels.json @@ -0,0 +1,121 @@ +{ + "runOn": [ + { + "minServerVersion": "4.3.1", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "tests": [ + { + "description": "FindOneAndReplace succeeds with RetryableWriteError from server", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "errorCode": 112, + "errorLabels": [ + "RetryableWriteError" + ] + } + }, + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": 111 + }, + "returnDocument": "Before" + } + }, + "outcome": { + "result": { + "_id": 1, + "x": 11 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 111 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + }, + { + "description": "FindOneAndReplace fails if server does not return RetryableWriteError", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "errorCode": 11600, + "errorLabels": [] + } + }, + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": 111 + }, + "returnDocument": "Before" + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + } + ] +} diff --git a/test/retryable_writes/findOneAndReplace-serverErrors.json b/test/retryable_writes/findOneAndReplace-serverErrors.json index d5d25e1d7..6ebe057cf 100644 --- a/test/retryable_writes/findOneAndReplace-serverErrors.json +++ b/test/retryable_writes/findOneAndReplace-serverErrors.json @@ -35,7 +35,10 @@ "failCommands": [ "findAndModify" ], - "errorCode": 189 + "errorCode": 189, + "errorLabels": [ + "RetryableWriteError" + ] } }, "operation": { @@ -83,7 +86,10 @@ ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -118,6 +124,54 @@ ] } } + }, + { + "description": "FindOneAndReplace fails with a RetryableWriteError label after two connection failures", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "closeConnection": true + } + }, + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": 111 + }, + "returnDocument": "Before" + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsContain": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } } ] } diff --git a/test/retryable_writes/findOneAndUpdate-errorLabels.json b/test/retryable_writes/findOneAndUpdate-errorLabels.json new file mode 100644 index 000000000..1926d7fa5 --- /dev/null +++ b/test/retryable_writes/findOneAndUpdate-errorLabels.json @@ -0,0 +1,123 @@ +{ + "runOn": [ + { + "minServerVersion": "4.3.1", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "tests": [ + { + "description": "FindOneAndUpdate succeeds with RetryableWriteError from server", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "errorCode": 112, + "errorLabels": [ + "RetryableWriteError" + ] + } + }, + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "returnDocument": "Before" + } + }, + "outcome": { + "result": { + "_id": 1, + "x": 11 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 12 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate fails if server does not return RetryableWriteError", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "errorCode": 11600, + "errorLabels": [] + } + }, + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "returnDocument": "Before" + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + } + ] +} diff --git a/test/retryable_writes/findOneAndUpdate-serverErrors.json b/test/retryable_writes/findOneAndUpdate-serverErrors.json index b9f57cd82..e6e369c13 100644 --- a/test/retryable_writes/findOneAndUpdate-serverErrors.json +++ b/test/retryable_writes/findOneAndUpdate-serverErrors.json @@ -35,7 +35,10 @@ "failCommands": [ "findAndModify" ], - "errorCode": 189 + "errorCode": 189, + "errorLabels": [ + "RetryableWriteError" + ] } }, "operation": { @@ -84,7 +87,10 @@ ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -120,6 +126,55 @@ ] } } + }, + { + "description": "FindOneAndUpdate fails with a RetryableWriteError label after two connection failures", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "closeConnection": true + } + }, + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "returnDocument": "Before" + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsContain": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } } ] } diff --git a/test/retryable_writes/insertMany-errorLabels.json b/test/retryable_writes/insertMany-errorLabels.json new file mode 100644 index 000000000..c78946e90 --- /dev/null +++ b/test/retryable_writes/insertMany-errorLabels.json @@ -0,0 +1,129 @@ +{ + "runOn": [ + { + "minServerVersion": "4.3.1", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "data": [ + { + "_id": 1, + "x": 11 + } + ], + "tests": [ + { + "description": "InsertMany succeeds with RetryableWriteError from server", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorCode": 112, + "errorLabels": [ + "RetryableWriteError" + ] + } + }, + "operation": { + "name": "insertMany", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "options": { + "ordered": true + } + } + }, + "outcome": { + "result": { + "insertedIds": { + "0": 2, + "1": 3 + } + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "InsertMany fails if server does not return RetryableWriteError", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorCode": 11600, + "errorLabels": [] + } + }, + "operation": { + "name": "insertMany", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "options": { + "ordered": true + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + } + ] + } + } + } + ] +} diff --git a/test/retryable_writes/insertMany-serverErrors.json b/test/retryable_writes/insertMany-serverErrors.json index 773ad9307..1c6ebafc2 100644 --- a/test/retryable_writes/insertMany-serverErrors.json +++ b/test/retryable_writes/insertMany-serverErrors.json @@ -31,7 +31,10 @@ "failCommands": [ "insert" ], - "errorCode": 189 + "errorCode": 189, + "errorLabels": [ + "RetryableWriteError" + ] } }, "operation": { @@ -90,7 +93,10 @@ ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -136,6 +142,55 @@ ] } } + }, + { + "description": "InsertMany fails with a RetryableWriteError label after two connection failures", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "insert" + ], + "closeConnection": true + } + }, + "operation": { + "name": "insertMany", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "options": { + "ordered": true + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsContain": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + } + ] + } + } } ] } diff --git a/test/retryable_writes/insertOne-errorLabels.json b/test/retryable_writes/insertOne-errorLabels.json new file mode 100644 index 000000000..9b8d13d52 --- /dev/null +++ b/test/retryable_writes/insertOne-errorLabels.json @@ -0,0 +1,90 @@ +{ + "runOn": [ + { + "minServerVersion": "4.3.1", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "data": [], + "tests": [ + { + "description": "InsertOne succeeds with RetryableWriteError from server", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorCode": 112, + "errorLabels": [ + "RetryableWriteError" + ] + } + }, + "operation": { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "x": 11 + } + } + }, + "outcome": { + "result": { + "insertedId": 1 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + } + ] + } + } + }, + { + "description": "InsertOne fails if server does not return RetryableWriteError", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorCode": 11600, + "errorLabels": [] + } + }, + "operation": { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "x": 11 + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [] + } + } + } + ] +} diff --git a/test/retryable_writes/insertOne-serverErrors.json b/test/retryable_writes/insertOne-serverErrors.json index 703ac1e15..59f6d9b51 100644 --- a/test/retryable_writes/insertOne-serverErrors.json +++ b/test/retryable_writes/insertOne-serverErrors.json @@ -69,6 +69,53 @@ } } }, + { + "description": "InsertOne fails after connection failure when retryWrites option is false", + "clientOptions": { + "retryWrites": false + }, + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "closeConnection": true + } + }, + "operation": { + "name": "insertOne", + "arguments": { + "document": { + "_id": 3, + "x": 33 + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + }, { "description": "InsertOne succeeds after NotMaster", "failPoint": { @@ -81,6 +128,9 @@ "insert" ], "errorCode": 10107, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -127,6 +177,9 @@ "insert" ], "errorCode": 13436, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -173,6 +226,9 @@ "insert" ], "errorCode": 13435, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -219,6 +275,9 @@ "insert" ], "errorCode": 11602, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -265,6 +324,9 @@ "insert" ], "errorCode": 11600, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -311,6 +373,9 @@ "insert" ], "errorCode": 189, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -357,6 +422,9 @@ "insert" ], "errorCode": 91, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -403,6 +471,9 @@ "insert" ], "errorCode": 7, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -449,6 +520,9 @@ "insert" ], "errorCode": 6, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -495,6 +569,9 @@ "insert" ], "errorCode": 9001, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -541,6 +618,9 @@ "insert" ], "errorCode": 89, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -586,10 +666,11 @@ "failCommands": [ "insert" ], - "writeConcernError": { - "code": 262, - "closeConnection": false - } + "errorCode": 262, + "errorLabels": [ + "RetryableWriteError" + ], + "closeConnection": false } }, "operation": { @@ -649,6 +730,11 @@ }, "outcome": { "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, "collection": { "data": [ { @@ -676,7 +762,10 @@ ], "writeConcernError": { "code": 11600, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -724,7 +813,10 @@ ], "writeConcernError": { "code": 11602, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -772,7 +864,10 @@ ], "writeConcernError": { "code": 189, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -820,7 +915,10 @@ ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -883,6 +981,11 @@ }, "outcome": { "error": true, + "result": { + "errorLabelsContain": [ + "RetryableWriteError" + ] + }, "collection": { "data": [ { @@ -929,6 +1032,11 @@ }, "outcome": { "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, "collection": { "data": [ { @@ -979,6 +1087,11 @@ }, "outcome": { "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, "collection": { "data": [ { @@ -996,6 +1109,50 @@ ] } } + }, + { + "description": "InsertOne fails with a RetryableWriteError label after two connection failures", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "insert" + ], + "closeConnection": true + } + }, + "operation": { + "name": "insertOne", + "arguments": { + "document": { + "_id": 3, + "x": 33 + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsContain": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } } ] } diff --git a/test/retryable_writes/replaceOne-errorLabels.json b/test/retryable_writes/replaceOne-errorLabels.json new file mode 100644 index 000000000..06867e515 --- /dev/null +++ b/test/retryable_writes/replaceOne-errorLabels.json @@ -0,0 +1,120 @@ +{ + "runOn": [ + { + "minServerVersion": "4.3.1", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "tests": [ + { + "description": "ReplaceOne succeeds with RetryableWriteError from server", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "update" + ], + "errorCode": 112, + "errorLabels": [ + "RetryableWriteError" + ] + } + }, + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": 111 + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 111 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + }, + { + "description": "ReplaceOne fails if server does not return RetryableWriteError", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "update" + ], + "errorCode": 11600, + "errorLabels": [] + } + }, + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": 111 + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + } + ] +} diff --git a/test/retryable_writes/replaceOne-serverErrors.json b/test/retryable_writes/replaceOne-serverErrors.json index aac7b2f39..af18bcf1a 100644 --- a/test/retryable_writes/replaceOne-serverErrors.json +++ b/test/retryable_writes/replaceOne-serverErrors.json @@ -35,7 +35,10 @@ "failCommands": [ "update" ], - "errorCode": 189 + "errorCode": 189, + "errorLabels": [ + "RetryableWriteError" + ] } }, "operation": { @@ -83,7 +86,10 @@ ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -118,6 +124,53 @@ ] } } + }, + { + "description": "ReplaceOne fails with a RetryableWriteError label after two connection failures", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "update" + ], + "closeConnection": true + } + }, + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": 111 + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsContain": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } } ] } diff --git a/test/retryable_writes/updateOne-errorLabels.json b/test/retryable_writes/updateOne-errorLabels.json new file mode 100644 index 000000000..4a6be3ffb --- /dev/null +++ b/test/retryable_writes/updateOne-errorLabels.json @@ -0,0 +1,122 @@ +{ + "runOn": [ + { + "minServerVersion": "4.3.1", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "tests": [ + { + "description": "UpdateOne succeeds with RetryableWriteError from server", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "update" + ], + "errorCode": 112, + "errorLabels": [ + "RetryableWriteError" + ] + } + }, + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 12 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + }, + { + "description": "UpdateOne fails if server does not return RetryableWriteError", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "update" + ], + "errorCode": 11600, + "errorLabels": [] + } + }, + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsOmit": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + } + ] +} diff --git a/test/retryable_writes/updateOne-serverErrors.json b/test/retryable_writes/updateOne-serverErrors.json index 6f6c55dd5..bb442eb68 100644 --- a/test/retryable_writes/updateOne-serverErrors.json +++ b/test/retryable_writes/updateOne-serverErrors.json @@ -35,7 +35,10 @@ "failCommands": [ "update" ], - "errorCode": 189 + "errorCode": 189, + "errorLabels": [ + "RetryableWriteError" + ] } }, "operation": { @@ -84,7 +87,10 @@ ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -120,6 +126,54 @@ ] } } + }, + { + "description": "UpdateOne fails with a RetryableWriteError label after two connection failures", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "update" + ], + "closeConnection": true + } + }, + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "error": true, + "result": { + "errorLabelsContain": [ + "RetryableWriteError" + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } } ] } diff --git a/test/test_sdam_monitoring_spec.py b/test/test_sdam_monitoring_spec.py index 97412f41d..710bf8732 100644 --- a/test/test_sdam_monitoring_spec.py +++ b/test/test_sdam_monitoring_spec.py @@ -331,11 +331,13 @@ class TestSdamMonitoring(IntegrationTest): # changes because topologyVersion is not incremented. @client_context.require_version_max(4, 3) def test_not_master_error_publishes_events(self): - self._test_app_error({'errorCode': 10107, 'closeConnection': False}, + self._test_app_error({'errorCode': 10107, 'closeConnection': False, + 'errorLabels': ['RetryableWriteError']}, NotMasterError) def test_shutdown_error_publishes_events(self): - self._test_app_error({'errorCode': 91, 'closeConnection': False}, + self._test_app_error({'errorCode': 91, 'closeConnection': False, + 'errorLabels': ['RetryableWriteError']}, NotMasterError) diff --git a/test/transactions-convenient-api/commit-retry.json b/test/transactions-convenient-api/commit-retry.json index d4b948ce1..312116253 100644 --- a/test/transactions-convenient-api/commit-retry.json +++ b/test/transactions-convenient-api/commit-retry.json @@ -304,6 +304,9 @@ "commitTransaction" ], "errorCode": 10107, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, diff --git a/test/transactions/bulk.json b/test/transactions/bulk.json index ea4571c1d..8a9793b8b 100644 --- a/test/transactions/bulk.json +++ b/test/transactions/bulk.json @@ -304,9 +304,7 @@ "$set": { "x": 1 } - }, - "multi": false, - "upsert": false + } }, { "q": { @@ -317,7 +315,6 @@ "x": 2 } }, - "multi": false, "upsert": true } ], @@ -379,9 +376,7 @@ }, "u": { "y": 1 - }, - "multi": false, - "upsert": false + } }, { "q": { @@ -389,9 +384,7 @@ }, "u": { "y": 2 - }, - "multi": false, - "upsert": false + } } ], "ordered": true, @@ -454,8 +447,7 @@ "z": 1 } }, - "multi": true, - "upsert": false + "multi": true } ], "ordered": true, diff --git a/test/transactions/causal-consistency.json b/test/transactions/causal-consistency.json index f1ca3d83a..0e81bf2ff 100644 --- a/test/transactions/causal-consistency.json +++ b/test/transactions/causal-consistency.json @@ -40,8 +40,7 @@ "$inc": { "count": 1 } - }, - "upsert": false + } }, "result": { "matchedCount": 1, @@ -65,8 +64,7 @@ "$inc": { "count": 1 } - }, - "upsert": false + } }, "result": { "matchedCount": 1, @@ -93,9 +91,7 @@ "$inc": { "count": 1 } - }, - "multi": false, - "upsert": false + } } ], "ordered": true, @@ -123,9 +119,7 @@ "$inc": { "count": 1 } - }, - "multi": false, - "upsert": false + } } ], "ordered": true, @@ -212,8 +206,7 @@ "$inc": { "count": 1 } - }, - "upsert": false + } }, "result": { "matchedCount": 1, @@ -260,9 +253,7 @@ "$inc": { "count": 1 } - }, - "multi": false, - "upsert": false + } } ], "ordered": true, diff --git a/test/transactions/error-labels.json b/test/transactions/error-labels.json index 8662b6d76..2d3eed3cc 100644 --- a/test/transactions/error-labels.json +++ b/test/transactions/error-labels.json @@ -134,6 +134,7 @@ "TransientTransactionError" ], "errorLabelsOmit": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ] } @@ -223,6 +224,7 @@ "TransientTransactionError" ], "errorLabelsOmit": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ] } @@ -312,6 +314,7 @@ "TransientTransactionError" ], "errorLabelsOmit": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ] } @@ -408,6 +411,7 @@ "TransientTransactionError" ], "errorLabelsOmit": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ] } @@ -461,7 +465,7 @@ } }, { - "description": "add transient label to connection errors", + "description": "add TransientTransactionError label to connection errors, but do not add RetryableWriteError label", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -496,6 +500,7 @@ "TransientTransactionError" ], "errorLabelsOmit": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ] } @@ -511,6 +516,7 @@ "TransientTransactionError" ], "errorLabelsOmit": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ] } @@ -533,6 +539,7 @@ "TransientTransactionError" ], "errorLabelsOmit": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ] } @@ -549,6 +556,7 @@ "TransientTransactionError" ], "errorLabelsOmit": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ] } @@ -663,7 +671,7 @@ } }, { - "description": "add unknown commit label to connection errors", + "description": "add RetryableWriteError and UnknownTransactionCommitResult labels to connection errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -699,6 +707,7 @@ "object": "session0", "result": { "errorLabelsContain": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ], "errorLabelsOmit": [ @@ -801,7 +810,7 @@ } }, { - "description": "add unknown commit label to retryable commit errors", + "description": "add RetryableWriteError and UnknownTransactionCommitResult labels to retryable commit errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -811,7 +820,10 @@ "failCommands": [ "commitTransaction" ], - "errorCode": 11602 + "errorCode": 11602, + "errorLabels": [ + "RetryableWriteError" + ] } }, "operations": [ @@ -837,6 +849,7 @@ "object": "session0", "result": { "errorLabelsContain": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ], "errorLabelsOmit": [ @@ -939,7 +952,7 @@ } }, { - "description": "add unknown commit label to writeConcernError ShutdownInProgress", + "description": "add RetryableWriteError and UnknownTransactionCommitResult labels to writeConcernError ShutdownInProgress", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -951,7 +964,10 @@ ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } }, @@ -985,6 +1001,7 @@ "object": "session0", "result": { "errorLabelsContain": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ], "errorLabelsOmit": [ @@ -1089,7 +1106,104 @@ } }, { - "description": "add unknown commit label to writeConcernError WriteConcernFailed", + "description": "do not add RetryableWriteError label to writeConcernError ShutdownInProgress that occurs within transaction", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "writeConcernError": { + "code": 91, + "errmsg": "Replication is being shut down" + } + } + }, + "operations": [ + { + "name": "startTransaction", + "object": "session0", + "arguments": { + "options": { + "writeConcern": { + "w": "majority" + } + } + } + }, + { + "name": "insertOne", + "object": "collection", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "result": { + "errorLabelsContain": [], + "errorLabelsOmit": [ + "RetryableWriteError", + "TransientTransactionError", + "UnknownTransactionCommitResult" + ] + } + }, + { + "name": "abortTransaction", + "object": "session0" + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1 + } + ], + "ordered": true, + "readConcern": null, + "lsid": "session0", + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": true, + "autocommit": false + }, + "command_name": "insert", + "database_name": "transaction-tests" + } + }, + { + "command_started_event": { + "command": { + "abortTransaction": 1, + "lsid": "session0", + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": null, + "autocommit": false + }, + "command_name": "abortTransaction", + "database_name": "admin" + } + } + ], + "outcome": { + "collection": { + "data": [] + } + } + }, + { + "description": "add UnknownTransactionCommitResult label to writeConcernError WriteConcernFailed", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -1138,6 +1252,7 @@ "UnknownTransactionCommitResult" ], "errorLabelsOmit": [ + "RetryableWriteError", "TransientTransactionError" ] } @@ -1220,7 +1335,7 @@ } }, { - "description": "add unknown commit label to writeConcernError WriteConcernFailed with wtimeout", + "description": "add UnknownTransactionCommitResult label to writeConcernError WriteConcernFailed with wtimeout", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -1273,6 +1388,7 @@ "UnknownTransactionCommitResult" ], "errorLabelsOmit": [ + "RetryableWriteError", "TransientTransactionError" ] } @@ -1355,7 +1471,7 @@ } }, { - "description": "omit unknown commit label to writeConcernError UnsatisfiableWriteConcern", + "description": "omit UnknownTransactionCommitResult label from writeConcernError UnsatisfiableWriteConcern", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -1401,6 +1517,7 @@ "object": "session0", "result": { "errorLabelsOmit": [ + "RetryableWriteError", "TransientTransactionError", "UnknownTransactionCommitResult" ] @@ -1461,7 +1578,7 @@ } }, { - "description": "omit unknown commit label to writeConcernError UnknownReplWriteConcern", + "description": "omit UnknownTransactionCommitResult label from writeConcernError UnknownReplWriteConcern", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -1507,6 +1624,7 @@ "object": "session0", "result": { "errorLabelsOmit": [ + "RetryableWriteConcern", "TransientTransactionError", "UnknownTransactionCommitResult" ] @@ -1567,7 +1685,7 @@ } }, { - "description": "do not add unknown commit label to MaxTimeMSExpired inside transactions", + "description": "do not add UnknownTransactionCommitResult label to MaxTimeMSExpired inside transactions", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -1614,6 +1732,7 @@ }, "result": { "errorLabelsOmit": [ + "RetryableWriteError", "UnknownTransactionCommitResult", "TransientTransactionError" ] @@ -1696,7 +1815,7 @@ } }, { - "description": "add unknown commit label to MaxTimeMSExpired", + "description": "add UnknownTransactionCommitResult label to MaxTimeMSExpired", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -1743,6 +1862,7 @@ "UnknownTransactionCommitResult" ], "errorLabelsOmit": [ + "RetryableWriteError", "TransientTransactionError" ] } @@ -1827,7 +1947,7 @@ } }, { - "description": "add unknown commit label to writeConcernError MaxTimeMSExpired", + "description": "add UnknownTransactionCommitResult label to writeConcernError MaxTimeMSExpired", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -1877,6 +1997,7 @@ "UnknownTransactionCommitResult" ], "errorLabelsOmit": [ + "RetryableWriteError", "TransientTransactionError" ] } diff --git a/test/transactions/mongos-recovery-token.json b/test/transactions/mongos-recovery-token.json index 50c7349c1..35ef45a03 100644 --- a/test/transactions/mongos-recovery-token.json +++ b/test/transactions/mongos-recovery-token.json @@ -181,7 +181,10 @@ ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down" + "errmsg": "Replication is being shut down", + "errorLabels": [ + "RetryableWriteError" + ] } } } diff --git a/test/transactions/pin-mongos.json b/test/transactions/pin-mongos.json index 5eb4fc57d..8e9d049d0 100644 --- a/test/transactions/pin-mongos.json +++ b/test/transactions/pin-mongos.json @@ -875,7 +875,7 @@ "failCommands": [ "commitTransaction" ], - "errorCode": 50 + "errorCode": 51 } } } @@ -887,7 +887,7 @@ "errorLabelsOmit": [ "TransientTransactionError" ], - "errorCode": 50 + "errorCode": 51 } }, { diff --git a/test/transactions/retryable-abort-errorLabels.json b/test/transactions/retryable-abort-errorLabels.json new file mode 100644 index 000000000..1110ce2c3 --- /dev/null +++ b/test/transactions/retryable-abort-errorLabels.json @@ -0,0 +1,204 @@ +{ + "runOn": [ + { + "minServerVersion": "4.3.1", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "transaction-tests", + "collection_name": "test", + "data": [], + "tests": [ + { + "description": "abortTransaction only retries once with RetryableWriteError from server", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "abortTransaction" + ], + "errorCode": 112, + "errorLabels": [ + "RetryableWriteError" + ] + } + }, + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "result": { + "insertedId": 1 + } + }, + { + "name": "abortTransaction", + "object": "session0" + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1 + } + ], + "ordered": true, + "readConcern": null, + "lsid": "session0", + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": true, + "autocommit": false, + "writeConcern": null + }, + "command_name": "insert", + "database_name": "transaction-tests" + } + }, + { + "command_started_event": { + "command": { + "abortTransaction": 1, + "lsid": "session0", + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": null, + "autocommit": false, + "writeConcern": null + }, + "command_name": "abortTransaction", + "database_name": "admin" + } + }, + { + "command_started_event": { + "command": { + "abortTransaction": 1, + "lsid": "session0", + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": null, + "autocommit": false, + "writeConcern": null + }, + "command_name": "abortTransaction", + "database_name": "admin" + } + } + ], + "outcome": { + "collection": { + "data": [] + } + } + }, + { + "description": "abortTransaction does not retry without RetryableWriteError label", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "abortTransaction" + ], + "errorCode": 11600, + "errorLabels": [] + } + }, + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "result": { + "insertedId": 1 + } + }, + { + "name": "abortTransaction", + "object": "session0" + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1 + } + ], + "ordered": true, + "readConcern": null, + "lsid": "session0", + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": true, + "autocommit": false, + "writeConcern": null + }, + "command_name": "insert", + "database_name": "transaction-tests" + } + }, + { + "command_started_event": { + "command": { + "abortTransaction": 1, + "lsid": "session0", + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": null, + "autocommit": false, + "writeConcern": null + }, + "command_name": "abortTransaction", + "database_name": "admin" + } + } + ], + "outcome": { + "collection": { + "data": [] + } + } + } + ] +} diff --git a/test/transactions/retryable-abort.json b/test/transactions/retryable-abort.json index f6b7b0e49..5a3aaa7bf 100644 --- a/test/transactions/retryable-abort.json +++ b/test/transactions/retryable-abort.json @@ -413,6 +413,9 @@ "abortTransaction" ], "errorCode": 10107, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -514,6 +517,9 @@ "abortTransaction" ], "errorCode": 13436, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -615,6 +621,9 @@ "abortTransaction" ], "errorCode": 13435, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -716,6 +725,9 @@ "abortTransaction" ], "errorCode": 11602, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -817,6 +829,9 @@ "abortTransaction" ], "errorCode": 11600, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -918,6 +933,9 @@ "abortTransaction" ], "errorCode": 189, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1019,6 +1037,9 @@ "abortTransaction" ], "errorCode": 91, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1120,6 +1141,9 @@ "abortTransaction" ], "errorCode": 7, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1221,6 +1245,9 @@ "abortTransaction" ], "errorCode": 6, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1322,6 +1349,9 @@ "abortTransaction" ], "errorCode": 9001, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1423,6 +1453,9 @@ "abortTransaction" ], "errorCode": 89, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1525,6 +1558,9 @@ ], "writeConcernError": { "code": 11600, + "errorLabels": [ + "RetryableWriteError" + ], "errmsg": "Replication is being shut down" } } @@ -1639,6 +1675,9 @@ ], "writeConcernError": { "code": 11602, + "errorLabels": [ + "RetryableWriteError" + ], "errmsg": "Replication is being shut down" } } @@ -1753,6 +1792,9 @@ ], "writeConcernError": { "code": 189, + "errorLabels": [ + "RetryableWriteError" + ], "errmsg": "Replication is being shut down" } } @@ -1867,6 +1909,9 @@ ], "writeConcernError": { "code": 91, + "errorLabels": [ + "RetryableWriteError" + ], "errmsg": "Replication is being shut down" } } diff --git a/test/transactions/retryable-commit-errorLabels.json b/test/transactions/retryable-commit-errorLabels.json new file mode 100644 index 000000000..e0818f237 --- /dev/null +++ b/test/transactions/retryable-commit-errorLabels.json @@ -0,0 +1,223 @@ +{ + "runOn": [ + { + "minServerVersion": "4.3.1", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "transaction-tests", + "collection_name": "test", + "data": [], + "tests": [ + { + "description": "commitTransaction does not retry error without RetryableWriteError label", + "clientOptions": { + "retryWrites": false + }, + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "commitTransaction" + ], + "errorCode": 11600, + "errorLabels": [] + } + }, + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "result": { + "insertedId": 1 + } + }, + { + "name": "commitTransaction", + "object": "session0", + "result": { + "errorLabelsOmit": [ + "RetryableWriteError", + "TransientTransactionError" + ] + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1 + } + ], + "ordered": true, + "readConcern": null, + "lsid": "session0", + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": true, + "autocommit": false, + "writeConcern": null + }, + "command_name": "insert", + "database_name": "transaction-tests" + } + }, + { + "command_started_event": { + "command": { + "commitTransaction": 1, + "lsid": "session0", + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": null, + "autocommit": false, + "writeConcern": null + }, + "command_name": "commitTransaction", + "database_name": "admin" + } + } + ], + "outcome": { + "collection": { + "data": [] + } + } + }, + { + "description": "commitTransaction retries once with RetryableWriteError from server", + "clientOptions": { + "retryWrites": false + }, + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "commitTransaction" + ], + "errorCode": 112, + "errorLabels": [ + "RetryableWriteError" + ] + } + }, + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection", + "arguments": { + "session": "session0", + "document": { + "_id": 1 + } + }, + "result": { + "insertedId": 1 + } + }, + { + "name": "commitTransaction", + "object": "session0" + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1 + } + ], + "ordered": true, + "readConcern": null, + "lsid": "session0", + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": true, + "autocommit": false, + "writeConcern": null + }, + "command_name": "insert", + "database_name": "transaction-tests" + } + }, + { + "command_started_event": { + "command": { + "commitTransaction": 1, + "lsid": "session0", + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": null, + "autocommit": false, + "writeConcern": null + }, + "command_name": "commitTransaction", + "database_name": "admin" + } + }, + { + "command_started_event": { + "command": { + "commitTransaction": 1, + "lsid": "session0", + "txnNumber": { + "$numberLong": "1" + }, + "startTransaction": null, + "autocommit": false, + "writeConcern": { + "w": "majority", + "wtimeout": 10000 + } + }, + "command_name": "commitTransaction", + "database_name": "admin" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1 + } + ] + } + } + } + ] +} diff --git a/test/transactions/retryable-commit.json b/test/transactions/retryable-commit.json index b17438b70..4895c6e0c 100644 --- a/test/transactions/retryable-commit.json +++ b/test/transactions/retryable-commit.json @@ -57,6 +57,7 @@ "object": "session0", "result": { "errorLabelsContain": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ], "errorLabelsOmit": [ @@ -207,6 +208,7 @@ "object": "session0", "result": { "errorLabelsContain": [ + "RetryableWriteError", "UnknownTransactionCommitResult" ], "errorLabelsOmit": [ @@ -353,7 +355,9 @@ "result": { "errorCodeName": "Interrupted", "errorLabelsOmit": [ - "TransientTransactionError" + "RetryableWriteError", + "TransientTransactionError", + "UnknownTransactionCommitResult" ] } } @@ -406,7 +410,7 @@ } }, { - "description": "commitTransaction fails after WriteConcernError Interrupted", + "description": "commitTransaction is not retried after UnsatisfiableWriteConcern error", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -417,8 +421,8 @@ "commitTransaction" ], "writeConcernError": { - "code": 11601, - "errmsg": "operation was interrupted" + "code": 100, + "errmsg": "Not enough data-bearing nodes" } } }, @@ -452,7 +456,9 @@ "object": "session0", "result": { "errorLabelsOmit": [ - "TransientTransactionError" + "RetryableWriteError", + "TransientTransactionError", + "UnknownTransactionCommitResult" ] } } @@ -629,6 +635,9 @@ "commitTransaction" ], "errorCode": 10107, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -737,6 +746,9 @@ "commitTransaction" ], "errorCode": 13436, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -845,6 +857,9 @@ "commitTransaction" ], "errorCode": 13435, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -953,6 +968,9 @@ "commitTransaction" ], "errorCode": 11602, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1061,6 +1079,9 @@ "commitTransaction" ], "errorCode": 11600, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1169,6 +1190,9 @@ "commitTransaction" ], "errorCode": 189, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1277,6 +1301,9 @@ "commitTransaction" ], "errorCode": 91, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1385,6 +1412,9 @@ "commitTransaction" ], "errorCode": 7, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1493,6 +1523,9 @@ "commitTransaction" ], "errorCode": 6, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1601,6 +1634,9 @@ "commitTransaction" ], "errorCode": 9001, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1709,6 +1745,9 @@ "commitTransaction" ], "errorCode": 89, + "errorLabels": [ + "RetryableWriteError" + ], "closeConnection": false } }, @@ -1818,6 +1857,9 @@ ], "writeConcernError": { "code": 11600, + "errorLabels": [ + "RetryableWriteError" + ], "errmsg": "Replication is being shut down" } } @@ -1937,6 +1979,9 @@ ], "writeConcernError": { "code": 11602, + "errorLabels": [ + "RetryableWriteError" + ], "errmsg": "Replication is being shut down" } } @@ -2056,6 +2101,9 @@ ], "writeConcernError": { "code": 189, + "errorLabels": [ + "RetryableWriteError" + ], "errmsg": "Replication is being shut down" } } @@ -2175,6 +2223,9 @@ ], "writeConcernError": { "code": 91, + "errorLabels": [ + "RetryableWriteError" + ], "errmsg": "Replication is being shut down" } } diff --git a/test/transactions/update.json b/test/transactions/update.json index 13cf2c926..e33bf5b81 100644 --- a/test/transactions/update.json +++ b/test/transactions/update.json @@ -116,7 +116,6 @@ "x": 1 } }, - "multi": false, "upsert": true } ], @@ -145,9 +144,7 @@ }, "u": { "y": 1 - }, - "multi": false, - "upsert": false + } } ], "ordered": true, @@ -179,8 +176,7 @@ "z": 1 } }, - "multi": true, - "upsert": false + "multi": true } ], "ordered": true, @@ -346,7 +342,6 @@ "x": 1 } }, - "multi": false, "upsert": true } ], @@ -375,9 +370,7 @@ }, "u": { "y": 1 - }, - "multi": false, - "upsert": false + } } ], "ordered": true, @@ -409,8 +402,7 @@ "z": 1 } }, - "multi": true, - "upsert": false + "multi": true } ], "ordered": true, diff --git a/test/transactions/write-concern.json b/test/transactions/write-concern.json index 88d062635..84b1ea365 100644 --- a/test/transactions/write-concern.json +++ b/test/transactions/write-concern.json @@ -877,7 +877,6 @@ "x": 1 } }, - "multi": false, "upsert": true } ],