From 09891a4ff3d9b2c04129fce4e5d273c13626b1ae Mon Sep 17 00:00:00 2001 From: Shane Harvey Date: Fri, 13 Apr 2018 14:08:23 -0700 Subject: [PATCH] Bring autoStartTransaction up to spec --- pymongo/client_session.py | 36 +++++++++++++++++------------------- pymongo/message.py | 2 +- pymongo/mongo_client.py | 3 ++- pymongo/network.py | 2 +- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/pymongo/client_session.py b/pymongo/client_session.py index af8b37720..9b0260e61 100644 --- a/pymongo/client_session.py +++ b/pymongo/client_session.py @@ -151,7 +151,7 @@ class _TransactionContext(object): return self def __exit__(self, exc_type, exc_val, exc_tb): - if self.__session.in_transaction: + if self.__session._in_transaction: if exc_val is None: self.__session.commit_transaction() else: @@ -175,8 +175,6 @@ class ClientSession(object): self._cluster_time = None self._operation_time = None self._transaction = None - if self.options.auto_start_transaction: - self.start_transaction() def end_session(self): """Finish this session. If a transaction has started, abort it. @@ -191,7 +189,7 @@ class ClientSession(object): def _end_session(self, lock): if self._server_session is not None: try: - if self.in_transaction: + if self._in_transaction: self.abort_transaction() finally: self._client._return_server_session(self._server_session, lock) @@ -259,7 +257,7 @@ class ClientSession(object): """ self._check_ended() - if self.in_transaction: + if self._in_transaction: raise InvalidOperation("Transaction already in progress") read_concern = self._inherit_option("read_concern", read_concern) @@ -284,7 +282,7 @@ class ClientSession(object): def _finish_transaction(self, command_name): self._check_ended() - if not self.in_transaction: + if not self._in_transaction_or_auto_start(): raise InvalidOperation("No transaction started") try: @@ -293,19 +291,12 @@ class ClientSession(object): self._server_session._transaction_id += 1 return - write_concern = self._transaction.opts.write_concern - if write_concern is None: - write_concern = self.client.write_concern - # TODO: retryable. And it's weird to pass parse_write_concern_error # from outside database.py. self._client.admin.command( command_name, - txnNumber=self._server_session.transaction_id, - stmtId=self._server_session.statement_id, session=self, - write_concern=write_concern, - read_preference=ReadPreference.PRIMARY, + write_concern=self._transaction.opts.write_concern, parse_write_concern_error=True) finally: self._server_session.reset_transaction() @@ -361,15 +352,22 @@ class ClientSession(object): return self._server_session is None @property - def in_transaction(self): + def _in_transaction(self): """True if this session has an active multi-statement transaction.""" return self._transaction is not None + def _in_transaction_or_auto_start(self): + """True if this session has an active transaction or will have one.""" + if self._in_transaction: + return True + if self.options.auto_start_transaction: + self.start_transaction() + return True + return False + def _apply_to(self, command, is_retryable, read_preference): self._check_ended() - - if self.options.auto_start_transaction and not self.in_transaction: - self.start_transaction() + self._in_transaction_or_auto_start() self._server_session.last_use = monotonic.time() command['lsid'] = self._server_session.session_id @@ -379,7 +377,7 @@ class ClientSession(object): command['txnNumber'] = self._server_session.transaction_id return - if self.in_transaction: + if self._in_transaction: if read_preference != ReadPreference.PRIMARY: raise InvalidOperation( 'read preference in a transaction must be primary, not: ' diff --git a/pymongo/message.py b/pymongo/message.py index 6fcc88d41..3e1efa27a 100644 --- a/pymongo/message.py +++ b/pymongo/message.py @@ -287,7 +287,7 @@ class _Query(object): # Explain does not support readConcern. if (not explain and session.options.causal_consistency and session.operation_time is not None - and not session.in_transaction): + and not session._in_transaction): cmd.setdefault( 'readConcern', {})[ 'afterClusterTime'] = session.operation_time diff --git a/pymongo/mongo_client.py b/pymongo/mongo_client.py index 73745c504..aa7231c78 100644 --- a/pymongo/mongo_client.py +++ b/pymongo/mongo_client.py @@ -1057,7 +1057,8 @@ class MongoClient(common.BaseObject): Re-raises any exception thrown by func(). """ retryable = (retryable and self.retry_writes - and session and not session.in_transaction) + and session + and not session._in_transaction_or_auto_start()) last_error = None retrying = False diff --git a/pymongo/network.py b/pymongo/network.py index d198c83ea..7f248f1f0 100644 --- a/pymongo/network.py +++ b/pymongo/network.py @@ -89,7 +89,7 @@ def command(sock, dbname, spec, slave_ok, is_mongos, spec['readConcern'] = read_concern.document if (session and session.options.causal_consistency and session.operation_time is not None - and not session.in_transaction): + and not session._in_transaction): spec.setdefault( 'readConcern', {})['afterClusterTime'] = session.operation_time if collation is not None: