)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":6460,"name":"Brad Topol","email":"btopol@us.ibm.com","username":"btopol"},"change_message_id":"50bb7e3a28b22256b093c20d127ce3f2502bcdc0","unresolved":false,"context_lines":[{"line_number":9,"context_line":"Due to the lack of support of `SELECT .. FOR UPDATE` call in"},{"line_number":10,"context_line":"MySQL + Galera, the use of `with_lockmode(\u0027update\u0027)` needs to be"},{"line_number":11,"context_line":"removed from the Trust SQL backend when utilizing the MySQL"},{"line_number":12,"context_line":"dialect. This change is haneled with an extra column for"},{"line_number":13,"context_line":"MySQL to leverage for locking the row in a separate transaction."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"The lock is performed within a context manager to ensure cleanup"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":4,"id":"1ae5cdf2_601671f3","line":12,"updated":"2014-06-08 16:16:31.000000000","message":"typo haneled should be handled","commit_id":"73f916900bc13d72f9184a6ec9cf5125ad3df874"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"dd4c12c9702dc3d6e960ac6d7d435667cdcd0cbc","unresolved":false,"context_lines":[{"line_number":9,"context_line":"Due to the lack of support of `SELECT .. FOR UPDATE` call in"},{"line_number":10,"context_line":"MySQL + Galera, the use of `with_lockmode(\u0027update\u0027)` needs to be"},{"line_number":11,"context_line":"removed from the Trust SQL backend when utilizing the MySQL"},{"line_number":12,"context_line":"dialect. This change is haneled with an extra column for"},{"line_number":13,"context_line":"MySQL to leverage for locking the row in a separate transaction."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"The lock is performed within a context manager to ensure cleanup"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":4,"id":"1ae5cdf2_70ae23e9","line":12,"in_reply_to":"1ae5cdf2_601671f3","updated":"2014-06-09 16:39:02.000000000","message":"Fixed in next patch.","commit_id":"73f916900bc13d72f9184a6ec9cf5125ad3df874"}],"keystone/common/sql/migrate_repo/versions/051_add_lock_to_trust_table_idempotent.py":[{"author":{"_account_id":6460,"name":"Brad Topol","email":"btopol@us.ibm.com","username":"btopol"},"change_message_id":"50bb7e3a28b22256b093c20d127ce3f2502bcdc0","unresolved":false,"context_lines":[{"line_number":19,"context_line":"    meta \u003d sqlalchemy.MetaData()"},{"line_number":20,"context_line":"    meta.bind \u003d migrate_engine"},{"line_number":21,"context_line":"    trust_table \u003d sqlalchemy.Table(\u0027trust\u0027, meta, autoload\u003dTrue)"},{"line_number":22,"context_line":"    # NOTE(morganfainberg): This upgrade may have occurred at revision 045."},{"line_number":23,"context_line":"    # Make sure the migration isn\u0027t tried again if it has already happened."},{"line_number":24,"context_line":"    if \u0027lock\u0027 not in trust_table.columns:"},{"line_number":25,"context_line":"        trust_table.create_column(sqlalchemy.Column(\u0027lock\u0027,"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_a0d79922","line":22,"updated":"2014-06-08 16:16:31.000000000","message":"Great comment! very helpful!","commit_id":"73f916900bc13d72f9184a6ec9cf5125ad3df874"},{"author":{"_account_id":6460,"name":"Brad Topol","email":"btopol@us.ibm.com","username":"btopol"},"change_message_id":"50bb7e3a28b22256b093c20d127ce3f2502bcdc0","unresolved":false,"context_lines":[{"line_number":28,"context_line":""},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"def downgrade(migrate_engine):"},{"line_number":31,"context_line":"    # NOTE(morganfainberg): There is no downgrade path since this is handled"},{"line_number":32,"context_line":"    # via a backport for icehouse, downgrade will occur at 045."},{"line_number":33,"context_line":"    pass"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_c0dca549","line":31,"updated":"2014-06-08 16:16:31.000000000","message":"Great comment! very helpful!","commit_id":"73f916900bc13d72f9184a6ec9cf5125ad3df874"}],"keystone/exception.py":[{"author":{"_account_id":1916,"name":"Guang Yee","email":"gyee@suse.com","username":"guang-yee"},"change_message_id":"44d9736e6261f337489a7bf5a4a7f56adac160f1","unresolved":false,"context_lines":[{"line_number":334,"context_line":""},{"line_number":335,"context_line":"class TrustConsumeMaximumAttempt(UnexpectedError):"},{"line_number":336,"context_line":"    debug_message_format \u003d _(\"Unable to consume trust %(trust_id)s, unable to \""},{"line_number":337,"context_line":"                             \"accquire lock.\")"},{"line_number":338,"context_line":""},{"line_number":339,"context_line":""},{"line_number":340,"context_line":"class CertificateFilesUnavailable(UnexpectedError):"}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_0241ce09","line":337,"updated":"2014-07-31 23:25:18.000000000","message":"\"unable to acquire database lock. Check database configuration.\"?","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"},{"author":{"_account_id":6486,"name":"Brant Knudson","email":"blk@acm.org","username":"blk-u"},"change_message_id":"94befb90d94fa68eebc0232b5852b563fb6b560b","unresolved":false,"context_lines":[{"line_number":334,"context_line":""},{"line_number":335,"context_line":"class TrustConsumeMaximumAttempt(UnexpectedError):"},{"line_number":336,"context_line":"    debug_message_format \u003d _(\"Unable to consume trust %(trust_id)s, unable to \""},{"line_number":337,"context_line":"                             \"accquire lock.\")"},{"line_number":338,"context_line":""},{"line_number":339,"context_line":""},{"line_number":340,"context_line":"class CertificateFilesUnavailable(UnexpectedError):"}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_857128e0","line":337,"updated":"2014-08-04 00:31:37.000000000","message":"change \"accquire\" to \"acquire\"","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"63a2551cc06019c19a8eab854c4ba4d560a7e4c4","unresolved":false,"context_lines":[{"line_number":334,"context_line":""},{"line_number":335,"context_line":"class TrustConsumeMaximumAttempt(UnexpectedError):"},{"line_number":336,"context_line":"    debug_message_format \u003d _(\"Unable to consume trust %(trust_id)s, unable to \""},{"line_number":337,"context_line":"                             \"accquire lock.\")"},{"line_number":338,"context_line":""},{"line_number":339,"context_line":""},{"line_number":340,"context_line":"class CertificateFilesUnavailable(UnexpectedError):"}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_f88c6dda","line":337,"in_reply_to":"baada198_0241ce09","updated":"2014-08-01 16:36:00.000000000","message":"This is less of a DB configuration issue and more of a DB contention issue. You should never see this unless you are issuing a bunch of tokens from the same trust across multiple keystone processes in a tight loop","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"2bf7b17f3e9ddf592bcb6f88bc79a3baefd2bc91","unresolved":false,"context_lines":[{"line_number":334,"context_line":""},{"line_number":335,"context_line":"class TrustConsumeMaximumAttempt(UnexpectedError):"},{"line_number":336,"context_line":"    debug_message_format \u003d _(\"Unable to consume trust %(trust_id)s, unable to \""},{"line_number":337,"context_line":"                             \"accquire lock.\")"},{"line_number":338,"context_line":""},{"line_number":339,"context_line":""},{"line_number":340,"context_line":"class CertificateFilesUnavailable(UnexpectedError):"}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_bb946f36","line":337,"in_reply_to":"baada198_857128e0","updated":"2014-08-04 16:59:49.000000000","message":"Done","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"},{"author":{"_account_id":6486,"name":"Brant Knudson","email":"blk@acm.org","username":"blk-u"},"change_message_id":"087d4c2635ade3d9d5ef830c14cfc7a0a60be1c3","unresolved":false,"context_lines":[{"line_number":334,"context_line":""},{"line_number":335,"context_line":"class TrustConsumeMaximumAttempt(UnexpectedError):"},{"line_number":336,"context_line":"    debug_message_format \u003d _(\"Unable to consume trust %(trust_id)s, unable to \""},{"line_number":337,"context_line":"                             \"acquire lock.\")"},{"line_number":338,"context_line":""},{"line_number":339,"context_line":""},{"line_number":340,"context_line":"class CertificateFilesUnavailable(UnexpectedError):"}],"source_content_type":"text/x-python","patch_set":17,"id":"baada198_84210051","line":337,"updated":"2014-08-04 23:35:58.000000000","message":"it actually would be useful to mention that the lock is in the database.","commit_id":"0724fc4d27c90461de3310b3b2cb7387e6c92bba"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"01fbcce574e997cd1c87c9878b5c732a1b782705","unresolved":false,"context_lines":[{"line_number":334,"context_line":""},{"line_number":335,"context_line":"class TrustConsumeMaximumAttempt(UnexpectedError):"},{"line_number":336,"context_line":"    debug_message_format \u003d _(\"Unable to consume trust %(trust_id)s, unable to \""},{"line_number":337,"context_line":"                             \"acquire lock.\")"},{"line_number":338,"context_line":""},{"line_number":339,"context_line":""},{"line_number":340,"context_line":"class CertificateFilesUnavailable(UnexpectedError):"}],"source_content_type":"text/x-python","patch_set":17,"id":"baada198_05b4071b","line":337,"in_reply_to":"baada198_84210051","updated":"2014-08-05 04:08:53.000000000","message":"If we need a new patch, will include this.","commit_id":"0724fc4d27c90461de3310b3b2cb7387e6c92bba"}],"keystone/tests/test_backend_sql.py":[{"author":{"_account_id":6460,"name":"Brad Topol","email":"btopol@us.ibm.com","username":"btopol"},"change_message_id":"50bb7e3a28b22256b093c20d127ce3f2502bcdc0","unresolved":false,"context_lines":[{"line_number":343,"context_line":""},{"line_number":344,"context_line":"        # Check that the context manager properly cleans up after itself."},{"line_number":345,"context_line":"        sql_model \u003d self._get_direct_sql_model_of_trust(trust_id)"},{"line_number":346,"context_line":"        self.assertIsNone(sql_model.lock)"},{"line_number":347,"context_line":""},{"line_number":348,"context_line":"    def test_trust_row_locking_lock_trust_already_locked(self):"},{"line_number":349,"context_line":"        # Create the replacement _lock_trust_record function to ensure we"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_00a20d9a","line":346,"updated":"2014-06-08 16:16:31.000000000","message":"I understand how you are verifying how the context manager properly cleans up after itself, but what is the action that  automatically causes the context manager to clean up after itself?","commit_id":"73f916900bc13d72f9184a6ec9cf5125ad3df874"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"dd4c12c9702dc3d6e960ac6d7d435667cdcd0cbc","unresolved":false,"context_lines":[{"line_number":343,"context_line":""},{"line_number":344,"context_line":"        # Check that the context manager properly cleans up after itself."},{"line_number":345,"context_line":"        sql_model \u003d self._get_direct_sql_model_of_trust(trust_id)"},{"line_number":346,"context_line":"        self.assertIsNone(sql_model.lock)"},{"line_number":347,"context_line":""},{"line_number":348,"context_line":"    def test_trust_row_locking_lock_trust_already_locked(self):"},{"line_number":349,"context_line":"        # Create the replacement _lock_trust_record function to ensure we"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_f025d3ae","line":346,"in_reply_to":"1ae5cdf2_00a20d9a","updated":"2014-06-09 16:39:02.000000000","message":"If you look at the context manager, the part up to \u0027yield\u0027 is executed before the block within the \u0027with\u0027 statement, and the part after yield is executed once you\u0027re out of the with statement.\n\nthis could be accomplished with a try/finally (context managers are just nice syntactic sugar)","commit_id":"73f916900bc13d72f9184a6ec9cf5125ad3df874"},{"author":{"_account_id":6460,"name":"Brad Topol","email":"btopol@us.ibm.com","username":"btopol"},"change_message_id":"50bb7e3a28b22256b093c20d127ce3f2502bcdc0","unresolved":false,"context_lines":[{"line_number":398,"context_line":"                                          use_row_lock\u003dTrue) as lock_id:"},{"line_number":399,"context_line":"            self.assertIsNotNone(lock_id)"},{"line_number":400,"context_line":"            sql_model \u003d self._get_direct_sql_model_of_trust(trust_id)"},{"line_number":401,"context_line":"            self.assertIsNone(sql_model.lock)"},{"line_number":402,"context_line":""},{"line_number":403,"context_line":"    def test_get_trust_lock_value_not_included(self):"},{"line_number":404,"context_line":"        trust_id \u003d uuid.uuid4().hex"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_8087fd11","line":401,"updated":"2014-06-08 16:16:31.000000000","message":"So you confirm unlimited trusts do not get locked by confirming sql_model.lock is none, correct?  Just curiously why is the self.assertIsNotNone(lock_id)  also needed?","commit_id":"73f916900bc13d72f9184a6ec9cf5125ad3df874"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"dd4c12c9702dc3d6e960ac6d7d435667cdcd0cbc","unresolved":false,"context_lines":[{"line_number":398,"context_line":"                                          use_row_lock\u003dTrue) as lock_id:"},{"line_number":399,"context_line":"            self.assertIsNotNone(lock_id)"},{"line_number":400,"context_line":"            sql_model \u003d self._get_direct_sql_model_of_trust(trust_id)"},{"line_number":401,"context_line":"            self.assertIsNone(sql_model.lock)"},{"line_number":402,"context_line":""},{"line_number":403,"context_line":"    def test_get_trust_lock_value_not_included(self):"},{"line_number":404,"context_line":"        trust_id \u003d uuid.uuid4().hex"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_9d5ae84e","line":401,"in_reply_to":"1ae5cdf2_8087fd11","updated":"2014-06-09 16:39:02.000000000","message":"The isNotNone assert shows that we have a lock_id, the context manager yields (passes the information back in the with statement) the lock_id. \n\nIt\u0027s the responsibility of the external service to know if they hold the lock in a race condition.  The context manager should prevent it from racing, but be safe.","commit_id":"73f916900bc13d72f9184a6ec9cf5125ad3df874"}],"keystone/trust/backends/sql.py":[{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"fc39f8a8d8d6502261f6ee6e815988925e7dd6b2","unresolved":false,"context_lines":[{"line_number":81,"context_line":"                (session.query(TrustModel)."},{"line_number":82,"context_line":"                 filter_by(deleted_at\u003dNone)."},{"line_number":83,"context_line":"                 filter_by(id\u003dtrust_id)."},{"line_number":84,"context_line":"                 filter_by(remaining_uses\u003dNone)."},{"line_number":85,"context_line":"                 filter_by(lock\u003dNone).update({\u0027lock\u0027: lock_info}))"},{"line_number":86,"context_line":"        except sql.NotFound:"},{"line_number":87,"context_line":"            # NOTE(morganfainberg): Either the trust is gone or already"}],"source_content_type":"text/x-python","patch_set":2,"id":"1ae5cdf2_a4adcd8a","line":84,"updated":"2014-05-31 22:42:32.000000000","message":"This needs to be the inverse, remaining_uses must not be None","commit_id":"aa42749cf44404d6e0b5bc0982299f134c8af53e"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"fc39f8a8d8d6502261f6ee6e815988925e7dd6b2","unresolved":false,"context_lines":[{"line_number":100,"context_line":"                (session.query(TrustModel)."},{"line_number":101,"context_line":"                 filter_by(deleted_at\u003dNone)."},{"line_number":102,"context_line":"                 filter_by(id\u003dtrust_id)."},{"line_number":103,"context_line":"                 filter_by(remaining_uses\u003dNone)."},{"line_number":104,"context_line":"                 filter_by(lock\u003dlock_info).update({\u0027lock\u0027: None}))"},{"line_number":105,"context_line":"        except sql.NotFound:"},{"line_number":106,"context_line":"            # NOTE(morganfainberg): If we can\u0027t find the record to unlock"}],"source_content_type":"text/x-python","patch_set":2,"id":"1ae5cdf2_c4aad96f","line":103,"updated":"2014-05-31 22:42:32.000000000","message":"This needs to be the inverse, remaining_uses must not be None","commit_id":"aa42749cf44404d6e0b5bc0982299f134c8af53e"},{"author":{"_account_id":6460,"name":"Brad Topol","email":"btopol@us.ibm.com","username":"btopol"},"change_message_id":"50bb7e3a28b22256b093c20d127ce3f2502bcdc0","unresolved":false,"context_lines":[{"line_number":60,"context_line":"@contextlib.contextmanager"},{"line_number":61,"context_line":"def _lock_trust_record(trust_id, use_row_lock\u003dNone):"},{"line_number":62,"context_line":"    \"\"\"Lock a specific trust record in the DB."},{"line_number":63,"context_line":""},{"line_number":64,"context_line":"    This method should be used to lock a specific row in the DB with a"},{"line_number":65,"context_line":"    unique identifier. This is a workaround for the known issue with"},{"line_number":66,"context_line":"    MySQL+Galera and the \u0027SELECT ... FOR UPDATE\u0027 issues."}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_80b53dd2","line":63,"updated":"2014-06-08 16:16:31.000000000","message":"Great comment!","commit_id":"73f916900bc13d72f9184a6ec9cf5125ad3df874"},{"author":{"_account_id":6460,"name":"Brad Topol","email":"btopol@us.ibm.com","username":"btopol"},"change_message_id":"50bb7e3a28b22256b093c20d127ce3f2502bcdc0","unresolved":false,"context_lines":[{"line_number":111,"context_line":"                 filter_by(deleted_at\u003dNone)."},{"line_number":112,"context_line":"                 filter_by(id\u003dtrust_id)."},{"line_number":113,"context_line":"                 filter(TrustModel.remaining_uses.isnot(None))."},{"line_number":114,"context_line":"                 filter_by(lock\u003dlock_info).update({\u0027lock\u0027: None}))"},{"line_number":115,"context_line":"        except sql.NotFound:"},{"line_number":116,"context_line":"            # NOTE(morganfainberg): If we can\u0027t find the record to unlock"},{"line_number":117,"context_line":"            # there is no reason we should be raising an error, the record"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_60d751ee","line":114,"updated":"2014-06-08 16:16:31.000000000","message":"So,  since this is not the MySQL case you don\u0027t need  to use \u0027lock\u0027 and hence you set it to None, correct?","commit_id":"73f916900bc13d72f9184a6ec9cf5125ad3df874"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"dd4c12c9702dc3d6e960ac6d7d435667cdcd0cbc","unresolved":false,"context_lines":[{"line_number":111,"context_line":"                 filter_by(deleted_at\u003dNone)."},{"line_number":112,"context_line":"                 filter_by(id\u003dtrust_id)."},{"line_number":113,"context_line":"                 filter(TrustModel.remaining_uses.isnot(None))."},{"line_number":114,"context_line":"                 filter_by(lock\u003dlock_info).update({\u0027lock\u0027: None}))"},{"line_number":115,"context_line":"        except sql.NotFound:"},{"line_number":116,"context_line":"            # NOTE(morganfainberg): If we can\u0027t find the record to unlock"},{"line_number":117,"context_line":"            # there is no reason we should be raising an error, the record"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_30573b04","line":114,"in_reply_to":"1ae5cdf2_60d751ee","updated":"2014-06-09 16:39:02.000000000","message":"Correct. If it\u0027s not MySQL, lock_info will be None, there is nothing to do.","commit_id":"73f916900bc13d72f9184a6ec9cf5125ad3df874"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"44c80a7743c9d522b454109be62a32b09f16470b","unresolved":false,"context_lines":[{"line_number":97,"context_line":"            # NOTE(morganfainberg): Either the trust is gone or already"},{"line_number":98,"context_line":"            # locked. It is the responsibility of the method using the context"},{"line_number":99,"context_line":"            # to figure out if the trust is locked or gone."},{"line_number":100,"context_line":"            pass"},{"line_number":101,"context_line":""},{"line_number":102,"context_line":"    # NOTE(morganfainberg): The lock_info should be used externally to"},{"line_number":103,"context_line":"    # check that the context still holds the lock before performing any"}],"source_content_type":"text/x-python","patch_set":7,"id":"1ae5cdf2_debf9dfa","line":100,"updated":"2014-06-26 18:11:10.000000000","message":"it seems like this wont actually block if the lock is taken.","commit_id":"2de781008288d52c387ac02ef3bfb386abb265e6"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"44c80a7743c9d522b454109be62a32b09f16470b","unresolved":false,"context_lines":[{"line_number":154,"context_line":""},{"line_number":155,"context_line":"    @sql.handle_conflicts(conflict_type\u003d\u0027trust\u0027)"},{"line_number":156,"context_line":"    def consume_use(self, trust_id):"},{"line_number":157,"context_line":"        with _lock_trust_record(trust_id) as lock_id:"},{"line_number":158,"context_line":"            with sql.transaction() as session:"},{"line_number":159,"context_line":"                if lock_id is None:"},{"line_number":160,"context_line":"                    # NOTE(morganfainberg): lock_id will be None if the dialect"}],"source_content_type":"text/x-python","patch_set":7,"id":"1ae5cdf2_fe6619bb","line":157,"updated":"2014-06-26 18:11:10.000000000","message":"this part of the code seems like, we are using _lock_trust_record to make a decision about locking, but then we have these two conditional paths anyway.  Can\u0027t we move the \"query(TrustModel).with_lockmode(\u0027update\u0027) part into _lock_trust_record also?  since that is basically the \"other way\" to lock.    Also is it required that _lock_trust_record and consume_use use two distinct transactions?  (im not sure what sql.transaction() does exactly, are these just nested transactions ?)","commit_id":"2de781008288d52c387ac02ef3bfb386abb265e6"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"6ee4979e08a2033f92e948911808764245f8664b","unresolved":false,"context_lines":[{"line_number":154,"context_line":""},{"line_number":155,"context_line":"    @sql.handle_conflicts(conflict_type\u003d\u0027trust\u0027)"},{"line_number":156,"context_line":"    def consume_use(self, trust_id):"},{"line_number":157,"context_line":"        with _lock_trust_record(trust_id) as lock_id:"},{"line_number":158,"context_line":"            with sql.transaction() as session:"},{"line_number":159,"context_line":"                if lock_id is None:"},{"line_number":160,"context_line":"                    # NOTE(morganfainberg): lock_id will be None if the dialect"}],"source_content_type":"text/x-python","patch_set":7,"id":"1ae5cdf2_fec29952","line":157,"in_reply_to":"1ae5cdf2_fe6619bb","updated":"2014-06-26 18:13:21.000000000","message":"sql.transaction is just a \"get session, session.begin\" wrapper/context manager. It saves on duplicated code we use all over.","commit_id":"2de781008288d52c387ac02ef3bfb386abb265e6"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"c3f71939c4b0395da992d0501d028740ced9ccc1","unresolved":false,"context_lines":[{"line_number":80,"context_line":"    def consume_use(self, trust_id):"},{"line_number":81,"context_line":"        consume_attempts \u003d 0"},{"line_number":82,"context_line":""},{"line_number":83,"context_line":"        while True:"},{"line_number":84,"context_line":"            consume_attempts +\u003d 1"},{"line_number":85,"context_line":"            with sql.transaction() as session:"},{"line_number":86,"context_line":"                # NOTE(morganfainberg): We only need the remaining_uses here"}],"source_content_type":"text/x-python","patch_set":10,"id":"dab895d6_a2497f8d","line":83,"updated":"2014-06-29 18:36:15.000000000","message":"how about:\n\n    for consume_attempt in six.range(MAXIMUM_CONSUME_ATTEMPTS):\n        # do thing\n        if \u003csuccess\u003e:\n           break\n    else:\n        raise exception.TrustConsumeMaximumAttempt(...)\n\nsix.range() / xrange() is an iterator so no list is created.","commit_id":"5e133edd6747895ca4e036f42db9b67cf78c7e39"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"ba892475489f17b20d27723196425e8ab6f2bcfc","unresolved":false,"context_lines":[{"line_number":80,"context_line":"    def consume_use(self, trust_id):"},{"line_number":81,"context_line":"        consume_attempts \u003d 0"},{"line_number":82,"context_line":""},{"line_number":83,"context_line":"        while True:"},{"line_number":84,"context_line":"            consume_attempts +\u003d 1"},{"line_number":85,"context_line":"            with sql.transaction() as session:"},{"line_number":86,"context_line":"                # NOTE(morganfainberg): We only need the remaining_uses here"}],"source_content_type":"text/x-python","patch_set":10,"id":"baada198_d29f244f","line":83,"in_reply_to":"dab895d6_a2497f8d","updated":"2014-06-30 16:49:39.000000000","message":"++ in next patch.","commit_id":"5e133edd6747895ca4e036f42db9b67cf78c7e39"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"c3f71939c4b0395da992d0501d028740ced9ccc1","unresolved":false,"context_lines":[{"line_number":89,"context_line":"                # that will get updated."},{"line_number":90,"context_line":"                query_result \u003d (session.query(TrustModel.remaining_uses)."},{"line_number":91,"context_line":"                                filter_by(id\u003dtrust_id)."},{"line_number":92,"context_line":"                                filter_by(deleted_at\u003dNone).first())"},{"line_number":93,"context_line":""},{"line_number":94,"context_line":"                if query_result is None:"},{"line_number":95,"context_line":"                    raise exception.TrustNotFound(trust_id\u003dtrust_id)"}],"source_content_type":"text/x-python","patch_set":10,"id":"dab895d6_02586b55","line":92,"updated":"2014-06-29 18:36:15.000000000","message":"you can say:   \n\n   try:\n       remaining_uses \u003d session.query(...).filter_by(..).one()[0]\n   except orm_exc.NoResultFound:\n       raise exception.TrustNotFound(..)\n\none() will throw the exception if no rows returned so it\u0027s safe to call [0] on that result.","commit_id":"5e133edd6747895ca4e036f42db9b67cf78c7e39"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"ba892475489f17b20d27723196425e8ab6f2bcfc","unresolved":false,"context_lines":[{"line_number":89,"context_line":"                # that will get updated."},{"line_number":90,"context_line":"                query_result \u003d (session.query(TrustModel.remaining_uses)."},{"line_number":91,"context_line":"                                filter_by(id\u003dtrust_id)."},{"line_number":92,"context_line":"                                filter_by(deleted_at\u003dNone).first())"},{"line_number":93,"context_line":""},{"line_number":94,"context_line":"                if query_result is None:"},{"line_number":95,"context_line":"                    raise exception.TrustNotFound(trust_id\u003dtrust_id)"}],"source_content_type":"text/x-python","patch_set":10,"id":"baada198_328f8025","line":92,"in_reply_to":"dab895d6_02586b55","updated":"2014-06-30 16:49:39.000000000","message":"Great advice, will switch to it.","commit_id":"5e133edd6747895ca4e036f42db9b67cf78c7e39"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"c3f71939c4b0395da992d0501d028740ced9ccc1","unresolved":false,"context_lines":[{"line_number":108,"context_line":"                        filter_by(id\u003dtrust_id)."},{"line_number":109,"context_line":"                        filter_by(deleted_at\u003dNone)."},{"line_number":110,"context_line":"                        filter_by(remaining_uses\u003dremaining_uses)."},{"line_number":111,"context_line":"                        update({\u0027remaining_uses\u0027: (remaining_uses - 1)}))"},{"line_number":112,"context_line":"                    if rows_affected \u003d\u003d 1:"},{"line_number":113,"context_line":"                        # Successfully consumed a single limited-use trust."},{"line_number":114,"context_line":"                        # Since trust_id is the PK on the Trust table, there is"}],"source_content_type":"text/x-python","patch_set":10,"id":"dab895d6_e25a974f","line":111,"updated":"2014-06-29 18:36:15.000000000","message":"synchronize_session\u003dFalse inside of update()","commit_id":"5e133edd6747895ca4e036f42db9b67cf78c7e39"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"ba892475489f17b20d27723196425e8ab6f2bcfc","unresolved":false,"context_lines":[{"line_number":108,"context_line":"                        filter_by(id\u003dtrust_id)."},{"line_number":109,"context_line":"                        filter_by(deleted_at\u003dNone)."},{"line_number":110,"context_line":"                        filter_by(remaining_uses\u003dremaining_uses)."},{"line_number":111,"context_line":"                        update({\u0027remaining_uses\u0027: (remaining_uses - 1)}))"},{"line_number":112,"context_line":"                    if rows_affected \u003d\u003d 1:"},{"line_number":113,"context_line":"                        # Successfully consumed a single limited-use trust."},{"line_number":114,"context_line":"                        # Since trust_id is the PK on the Trust table, there is"}],"source_content_type":"text/x-python","patch_set":10,"id":"baada198_b2947045","line":111,"in_reply_to":"dab895d6_e25a974f","updated":"2014-06-30 16:49:39.000000000","message":"Done in next patch","commit_id":"5e133edd6747895ca4e036f42db9b67cf78c7e39"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"c3f71939c4b0395da992d0501d028740ced9ccc1","unresolved":false,"context_lines":[{"line_number":114,"context_line":"                        # Since trust_id is the PK on the Trust table, there is"},{"line_number":115,"context_line":"                        # no case we should match more than 1 row in the"},{"line_number":116,"context_line":"                        # update. We either update 1 row or 0 rows."},{"line_number":117,"context_line":"                        break"},{"line_number":118,"context_line":"                else:"},{"line_number":119,"context_line":"                    raise exception.TrustUseLimitReached(trust_id\u003dtrust_id)"},{"line_number":120,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"dab895d6_621da773","line":117,"updated":"2014-06-29 18:36:15.000000000","message":"should there perhaps be some kind of sleep() in between loops here?   doing ten queries in a tight loop might cut out other concurrent attempts, but i don\u0027t know eventlet\u0027s behavior that well here.","commit_id":"5e133edd6747895ca4e036f42db9b67cf78c7e39"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"ba892475489f17b20d27723196425e8ab6f2bcfc","unresolved":false,"context_lines":[{"line_number":114,"context_line":"                        # Since trust_id is the PK on the Trust table, there is"},{"line_number":115,"context_line":"                        # no case we should match more than 1 row in the"},{"line_number":116,"context_line":"                        # update. We either update 1 row or 0 rows."},{"line_number":117,"context_line":"                        break"},{"line_number":118,"context_line":"                else:"},{"line_number":119,"context_line":"                    raise exception.TrustUseLimitReached(trust_id\u003dtrust_id)"},{"line_number":120,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"baada198_b27b9028","line":117,"in_reply_to":"dab895d6_621da773","updated":"2014-06-30 16:49:39.000000000","message":"A sleep(0) would yield to another task, but Keystone runs mostly single threaded (and we\u0027re working to instead be under apache). A sleep \u003e 0 would be a bad idea.\n\nLet me ask the Keystone folks if they want a yield in here.","commit_id":"5e133edd6747895ca4e036f42db9b67cf78c7e39"},{"author":{"_account_id":11333,"name":"David J Hu","email":"david.hu@hpe.com","username":"dhu"},"change_message_id":"49deee31839a6e4de5525e17543016dbbad77f77","unresolved":false,"context_lines":[{"line_number":26,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":27,"context_line":"# The maximum number of iterations that will be attempted for optimistic"},{"line_number":28,"context_line":"# locking on consuming a limited-use trust."},{"line_number":29,"context_line":"MAXIMUM_CONSUME_ATTEMPTS \u003d 10"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"class TrustModel(sql.ModelBase, sql.DictBase):"}],"source_content_type":"text/x-python","patch_set":14,"id":"baada198_34458915","line":29,"updated":"2014-07-22 20:05:21.000000000","message":"Is 10 actually optimum?  Might be a good idea to make it tweakable via keystone.conf.","commit_id":"645c38f2d3837c7f87235d136a93c0977907e119"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"0dbf6989241407ad36f5e41a4f5faa3d8c2ed5a9","unresolved":false,"context_lines":[{"line_number":26,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":27,"context_line":"# The maximum number of iterations that will be attempted for optimistic"},{"line_number":28,"context_line":"# locking on consuming a limited-use trust."},{"line_number":29,"context_line":"MAXIMUM_CONSUME_ATTEMPTS \u003d 10"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"class TrustModel(sql.ModelBase, sql.DictBase):"}],"source_content_type":"text/x-python","patch_set":14,"id":"baada198_97299ef4","line":29,"in_reply_to":"baada198_34458915","updated":"2014-07-31 23:03:14.000000000","message":"I am not opposed to this being made configurable, however, I\u0027m not sure if there is a real benefit to it being configureable. If the general consensus is this should be configurable, I\u0027ll make it configurable (it\u0027s a few lines of code).I just don\u0027t want to add config options that really will never be changed,","commit_id":"645c38f2d3837c7f87235d136a93c0977907e119"},{"author":{"_account_id":11333,"name":"David J Hu","email":"david.hu@hpe.com","username":"dhu"},"change_message_id":"d8847b9dcec0c3858ea0e37770f507996bf791db","unresolved":false,"context_lines":[{"line_number":26,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":27,"context_line":"# The maximum number of iterations that will be attempted for optimistic"},{"line_number":28,"context_line":"# locking on consuming a limited-use trust."},{"line_number":29,"context_line":"MAXIMUM_CONSUME_ATTEMPTS \u003d 10"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"class TrustModel(sql.ModelBase, sql.DictBase):"}],"source_content_type":"text/x-python","patch_set":14,"id":"baada198_bf4e54c0","line":29,"in_reply_to":"baada198_97299ef4","updated":"2014-08-01 20:43:00.000000000","message":"10 for now.  I don\u0027t think we need to make it configurable unless there is a customer need.  Was just curious on how you came up with 10.","commit_id":"645c38f2d3837c7f87235d136a93c0977907e119"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"9607fb6fc0587a02b6de8760dcb9cf8672317fbe","unresolved":false,"context_lines":[{"line_number":26,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":27,"context_line":"# The maximum number of iterations that will be attempted for optimistic"},{"line_number":28,"context_line":"# locking on consuming a limited-use trust."},{"line_number":29,"context_line":"MAXIMUM_CONSUME_ATTEMPTS \u003d 10"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"class TrustModel(sql.ModelBase, sql.DictBase):"}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_574386af","line":29,"updated":"2014-07-31 23:03:41.000000000","message":"See comment on patchset 14.","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"},{"author":{"_account_id":11333,"name":"David J Hu","email":"david.hu@hpe.com","username":"dhu"},"change_message_id":"5276aac772472bfe7b4ce999bc2252c661705615","unresolved":false,"context_lines":[{"line_number":26,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":27,"context_line":"# The maximum number of iterations that will be attempted for optimistic"},{"line_number":28,"context_line":"# locking on consuming a limited-use trust."},{"line_number":29,"context_line":"MAXIMUM_CONSUME_ATTEMPTS \u003d 10"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"class TrustModel(sql.ModelBase, sql.DictBase):"}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_5fcb781c","line":29,"in_reply_to":"baada198_22709272","updated":"2014-08-01 20:43:40.000000000","message":"10 for now.  I don\u0027t think we need to make it configurable unless there is a customer need.  Was just curious on how you came up with 10.","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"},{"author":{"_account_id":1916,"name":"Guang Yee","email":"gyee@suse.com","username":"guang-yee"},"change_message_id":"44d9736e6261f337489a7bf5a4a7f56adac160f1","unresolved":false,"context_lines":[{"line_number":26,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":27,"context_line":"# The maximum number of iterations that will be attempted for optimistic"},{"line_number":28,"context_line":"# locking on consuming a limited-use trust."},{"line_number":29,"context_line":"MAXIMUM_CONSUME_ATTEMPTS \u003d 10"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"class TrustModel(sql.ModelBase, sql.DictBase):"}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_22709272","line":29,"in_reply_to":"baada198_574386af","updated":"2014-07-31 23:25:18.000000000","message":"I agree. Don\u0027t think it needs to be configurable. If 10 tries is not good, mostly like the database is fugged.","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"},{"author":{"_account_id":6486,"name":"Brant Knudson","email":"blk@acm.org","username":"blk-u"},"change_message_id":"94befb90d94fa68eebc0232b5852b563fb6b560b","unresolved":false,"context_lines":[{"line_number":83,"context_line":"    @sql.handle_conflicts(conflict_type\u003d\u0027trust\u0027)"},{"line_number":84,"context_line":"    def consume_use(self, trust_id):"},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"        for attempt in six.moves.range(MAXIMUM_CONSUME_ATTEMPTS):"},{"line_number":87,"context_line":"            with sql.transaction() as session:"},{"line_number":88,"context_line":"                # NOTE(morganfainberg): We only need the remaining_uses here"},{"line_number":89,"context_line":"                # so that we can avoid all the extra overhead of the ORM -\u003e"}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_e549048f","line":86,"updated":"2014-08-04 00:31:37.000000000","message":"suggest just use range.","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"2bf7b17f3e9ddf592bcb6f88bc79a3baefd2bc91","unresolved":false,"context_lines":[{"line_number":83,"context_line":"    @sql.handle_conflicts(conflict_type\u003d\u0027trust\u0027)"},{"line_number":84,"context_line":"    def consume_use(self, trust_id):"},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"        for attempt in six.moves.range(MAXIMUM_CONSUME_ATTEMPTS):"},{"line_number":87,"context_line":"            with sql.transaction() as session:"},{"line_number":88,"context_line":"                # NOTE(morganfainberg): We only need the remaining_uses here"},{"line_number":89,"context_line":"                # so that we can avoid all the extra overhead of the ORM -\u003e"}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_db976337","line":86,"in_reply_to":"baada198_e549048f","updated":"2014-08-04 16:59:49.000000000","message":"Done","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"},{"author":{"_account_id":6486,"name":"Brant Knudson","email":"blk@acm.org","username":"blk-u"},"change_message_id":"94befb90d94fa68eebc0232b5852b563fb6b560b","unresolved":false,"context_lines":[{"line_number":85,"context_line":""},{"line_number":86,"context_line":"        for attempt in six.moves.range(MAXIMUM_CONSUME_ATTEMPTS):"},{"line_number":87,"context_line":"            with sql.transaction() as session:"},{"line_number":88,"context_line":"                # NOTE(morganfainberg): We only need the remaining_uses here"},{"line_number":89,"context_line":"                # so that we can avoid all the extra overhead of the ORM -\u003e"},{"line_number":90,"context_line":"                # object book keeping. The remaining_uses is the only thing"},{"line_number":91,"context_line":"                # that will get updated."}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_85584858","line":88,"updated":"2014-08-04 00:31:37.000000000","message":"this comment seems pretty obvious. Suggest remove it.","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"2bf7b17f3e9ddf592bcb6f88bc79a3baefd2bc91","unresolved":false,"context_lines":[{"line_number":85,"context_line":""},{"line_number":86,"context_line":"        for attempt in six.moves.range(MAXIMUM_CONSUME_ATTEMPTS):"},{"line_number":87,"context_line":"            with sql.transaction() as session:"},{"line_number":88,"context_line":"                # NOTE(morganfainberg): We only need the remaining_uses here"},{"line_number":89,"context_line":"                # so that we can avoid all the extra overhead of the ORM -\u003e"},{"line_number":90,"context_line":"                # object book keeping. The remaining_uses is the only thing"},{"line_number":91,"context_line":"                # that will get updated."}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_1b9d5b57","line":88,"in_reply_to":"baada198_85584858","updated":"2014-08-04 16:59:49.000000000","message":"Done","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"},{"author":{"_account_id":6486,"name":"Brant Knudson","email":"blk@acm.org","username":"blk-u"},"change_message_id":"94befb90d94fa68eebc0232b5852b563fb6b560b","unresolved":false,"context_lines":[{"line_number":123,"context_line":"            # NOTE(morganfainberg): Ensure we have a yield point for eventlet"},{"line_number":124,"context_line":"            # here. This should cost us nothing otherwise. This can be removed"},{"line_number":125,"context_line":"            # if/when oslo.db cleanly handles yields on db calls."},{"line_number":126,"context_line":"            time.sleep(0)"},{"line_number":127,"context_line":"        else:"},{"line_number":128,"context_line":"            # NOTE(morganfainberg): In the case the for loop is not prematurely"},{"line_number":129,"context_line":"            # broken out of, this else block is executed. This means the trust"}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_8506881f","line":126,"updated":"2014-08-04 00:31:37.000000000","message":"there should be some delay here (expontial backoff). On a really fast system it could potentially take 0 seconds to do the operation and then there\u0027s no point in trying 10 times since you\u0027ll just get the same result every time.","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"2bf7b17f3e9ddf592bcb6f88bc79a3baefd2bc91","unresolved":false,"context_lines":[{"line_number":123,"context_line":"            # NOTE(morganfainberg): Ensure we have a yield point for eventlet"},{"line_number":124,"context_line":"            # here. This should cost us nothing otherwise. This can be removed"},{"line_number":125,"context_line":"            # if/when oslo.db cleanly handles yields on db calls."},{"line_number":126,"context_line":"            time.sleep(0)"},{"line_number":127,"context_line":"        else:"},{"line_number":128,"context_line":"            # NOTE(morganfainberg): In the case the for loop is not prematurely"},{"line_number":129,"context_line":"            # broken out of, this else block is executed. This means the trust"}],"source_content_type":"text/x-python","patch_set":15,"id":"baada198_1be1dbfb","line":126,"in_reply_to":"baada198_8506881f","updated":"2014-08-04 16:59:49.000000000","message":"This isn\u0027t blocking on a lock or waiting for a specific change, this is a \"query the db and get a row\" and then try and update with a specific \"where\" clause. If the db hasn\u0027t changed between the query and update you break out.  I don\u0027t see the win for having a backoff in the optimistic lock scenario. \n\nThis is really meant exclusively as a yield point for eventlet since eventlet + mysqldb doesn\u0027t play as well as we\u0027d like, if we didn\u0027t support eventlet I wouldn\u0027t expect to need a time.sleep() ever.\n\nIf there is a real/tangible benefit to a backoff here, I will add it, but honestly, I don\u0027t see it.","commit_id":"ba2dd3b3637160541f57de441a90df09abaacd10"}]}
