)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":9531,"name":"liuyulong","display_name":"LIU Yulong","email":"i@liuyulong.me","username":"LIU-Yulong"},"change_message_id":"2d6c5348cc3b222a2fee0ebfbc3aad493265fb69","unresolved":false,"context_lines":[{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Refactored RevisionPlugin to operate upon sets of objects at"},{"line_number":10,"context_line":"once.   In the case of \"related\" objects, the bump operation"},{"line_number":11,"context_line":"no longer makes use of compare-and-swap and instead updates"},{"line_number":12,"context_line":"version numbers directly without testing for their previous value."},{"line_number":13,"context_line":"This removes the issue of StaleDataErrors being"},{"line_number":14,"context_line":"prevalent within the related object update phase, given the assumption"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":8,"id":"9fdfeff1_4838b5ec","line":11,"range":{"start_line":11,"start_character":23,"end_line":11,"end_character":59},"updated":"2019-02-17 15:26:36.000000000","message":"I\u0027m not quite sure if this will break the following check:\n1. assuming two DB updating action coming from two parallelly API or RPC.\n2. the first one needs to update one attribute to A and revision +1.\n3. the second one needs to update one attribute to B and also revision +1.\n4. no matter which one updated the DB table first, (IIRC) the later one will get failed.\n\nSo after this change, the later one will be succeed or failed?","commit_id":"a9bc66fe9b27298267b29377870e9ead5ef7db4a"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"fd629906fa932439ac905c4b000b5836c7ea8780","unresolved":false,"context_lines":[{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Refactored RevisionPlugin to operate upon sets of objects at"},{"line_number":10,"context_line":"once.   In the case of \"related\" objects, the bump operation"},{"line_number":11,"context_line":"no longer makes use of compare-and-swap and instead updates"},{"line_number":12,"context_line":"version numbers directly without testing for their previous value."},{"line_number":13,"context_line":"This removes the issue of StaleDataErrors being"},{"line_number":14,"context_line":"prevalent within the related object update phase, given the assumption"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":8,"id":"9fdfeff1_cbfa5f41","line":11,"range":{"start_line":11,"start_character":23,"end_line":11,"end_character":59},"in_reply_to":"9fdfeff1_4838b5ec","updated":"2019-02-17 19:04:42.000000000","message":"barring the case of Galera multi-master write conflicts which are *always* possible for an HA installation that does not limit to a single master (e.g. not tripleo), it will succeed.  the mechanism by which these UPDATEs fail right now is on the Python side, counting the number of rows that match for an expected version id.   the change is that this check is removed; the row of a particular primary key is UPDATEd unconditionally using an increment relative to the version id that is there, so it succeeds every time.   InnoDB acts like READ COMMITTED on the UPDATE side of things even though its default isolation is called \"REPEATABLE READ\".   Background on this is at https://blog.pythian.com/understanding-mysql-isolation-levels-repeatable-read/.\n\nIn this case, the UPDATE has to actually read the row as well, so just to make sure, I ran tests for concurrent updates in two transactions.   Whether or not I target the same row, or I try to create a deadlock by targeting alternating rows (that is transaction A tries to target \u0027WHERE version_id\u003d1\", \"WHERE version_id\u003d2\" and transaction B tries \"WHERE version_id\u003d2\", \"WHERE version_id\u003d1\"), InnoDB is locking the table for the span of the transaction, so both UPDATEs succeed with the correct version identifier.  Note that this lock takes place in the same way using the existing logic so we are not adding any additional locks either.\n\nthe only difference here is that we are turning off SQLAlchemy\u0027s extra strict versioning check which wants to ensure no intermediary version number has come in since we started our transaction, and it is only for rows \"related\" to the primary thing we are changing.   The version is incremented by one in all cases.","commit_id":"a9bc66fe9b27298267b29377870e9ead5ef7db4a"}],"neutron/services/revisions/revision_plugin.py":[{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"58c8e085532cae3d8df6775bebfdf6dcf69c5d87","unresolved":false,"context_lines":[{"line_number":202,"context_line":"    def _run_constrained_instance_match_check(self, session, objects):"},{"line_number":203,"context_line":"        instance, match \u003d self._get_constrained_instance_match(session)"},{"line_number":204,"context_line":"        for obj in objects:"},{"line_number":205,"context_line":"            if instance and instance \u003d\u003d obj:"},{"line_number":206,"context_line":"                # one last check before bumping revision"},{"line_number":207,"context_line":"                self._enforce_if_match_constraints(session)"},{"line_number":208,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"9fdfeff1_1c592ffd","line":205,"updated":"2019-02-07 23:02:59.000000000","message":"I should put the \"if instance\" check above the loop here","commit_id":"2662ad5a5995eb01a87365fe61ad44a40b3350e3"},{"author":{"_account_id":11975,"name":"Slawek Kaplonski","email":"skaplons@redhat.com","username":"slaweq"},"change_message_id":"4aa109311914f90ea7d49e07b7b4d650cff46fa7","unresolved":false,"context_lines":[{"line_number":89,"context_line":"    def extend_resource_dict_revision(resource_res, resource_db):"},{"line_number":90,"context_line":"        resource_res[\u0027revision_number\u0027] \u003d resource_db.revision_number"},{"line_number":91,"context_line":""},{"line_number":92,"context_line":"    def _find_related_obj(self, session, obj, relationship_col):"},{"line_number":93,"context_line":"        \"\"\"Gets a related object off of a relationship."},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"        Raises a runtime error if the relationship isn\u0027t configured correctly"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_15656645","side":"PARENT","line":92,"updated":"2019-02-11 08:58:30.000000000","message":"nit: unrelated change","commit_id":"9a15084375a80df830cf50c1fb20908b5d7f822c"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"b70b5341d8dce8aeb9c4d3cc46eabfd99348b0d3","unresolved":false,"context_lines":[{"line_number":89,"context_line":"    def extend_resource_dict_revision(resource_res, resource_db):"},{"line_number":90,"context_line":"        resource_res[\u0027revision_number\u0027] \u003d resource_db.revision_number"},{"line_number":91,"context_line":""},{"line_number":92,"context_line":"    def _find_related_obj(self, session, obj, relationship_col):"},{"line_number":93,"context_line":"        \"\"\"Gets a related object off of a relationship."},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"        Raises a runtime error if the relationship isn\u0027t configured correctly"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_af6c4308","side":"PARENT","line":92,"in_reply_to":"9fdfeff1_15656645","updated":"2019-02-11 15:18:14.000000000","message":"I did this for clarity in that the session here is not used within the method.  The method does still emit queries in any case however (which was part of the problem with the tempest run).","commit_id":"9a15084375a80df830cf50c1fb20908b5d7f822c"},{"author":{"_account_id":11975,"name":"Slawek Kaplonski","email":"skaplons@redhat.com","username":"slaweq"},"change_message_id":"4aa109311914f90ea7d49e07b7b4d650cff46fa7","unresolved":false,"context_lines":[{"line_number":55,"context_line":"            session,"},{"line_number":56,"context_line":"            ["},{"line_number":57,"context_line":"                obj for obj in session.dirty"},{"line_number":58,"context_line":"                if isinstance(obj, standard_attr.HasStandardAttributes)]"},{"line_number":59,"context_line":"        )"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"        # see if any created/updated/deleted objects bump the revision"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_b5d01acb","line":58,"range":{"start_line":58,"start_character":71,"end_line":58,"end_character":72},"updated":"2019-02-11 08:58:30.000000000","message":"nitty nit: this could be moved to new line :)","commit_id":"7663e568172b4b7f1a83fdaf848b5aac05db6974"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"4179e2f1b50cb8a418c549a126b5e8b9f2661ce0","unresolved":false,"context_lines":[{"line_number":162,"context_line":"            obj for obj in objects if not getattr(obj, \u0027_rev_bumped\u0027, False)]"},{"line_number":163,"context_line":"        self._run_constrained_instance_match_check(session, to_bump)"},{"line_number":164,"context_line":""},{"line_number":165,"context_line":"        if not version_check:"},{"line_number":166,"context_line":"            # this UPDATE statement could alternatively be written to run"},{"line_number":167,"context_line":"            # as an UPDATE-per-object with Python-generated revision numbers"},{"line_number":168,"context_line":"            # as parameters."}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_3c9ca668","line":165,"updated":"2019-02-15 15:55:17.000000000","message":"I need to make this conditional if to_bump is empty","commit_id":"7663e568172b4b7f1a83fdaf848b5aac05db6974"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c7dca798d5da8cecbf12e6e8931131b94792c15","unresolved":false,"context_lines":[{"line_number":125,"context_line":"        related_obj \u003d getattr(obj, relationship_col)"},{"line_number":126,"context_line":"        if related_obj:"},{"line_number":127,"context_line":"            return related_obj"},{"line_number":128,"context_line":"        for rel in sqlalchemy.inspect(obj).mapper.relationships:"},{"line_number":129,"context_line":"            if rel.key !\u003d relationship_col:"},{"line_number":130,"context_line":"                continue"},{"line_number":131,"context_line":"            if not rel.load_on_pending:"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_1765fdb4","line":128,"updated":"2019-02-15 16:16:54.000000000","message":"as I work on a backport of this in newton, the irony is that the older approach, with some improvements, is probably cleaner; in that we do the \"lazy load from pending\" object here but don\u0027t require that the mappings be modified with the load_on_pending flag, which takes effect everywhere.   The individual objects here can have load_on_pending in a more limited scope using https://docs.sqlalchemy.org/en/latest/orm/session_api.html#sqlalchemy.orm.session.Session.enable_relationship_loading.  the dragon there is probably a little too severe, as it serves only to discourage the whole pattern that neutron has architected upon so we\u0027re already in the dragon\u0027s lair :)","commit_id":"1fa789c87b241b2f664aaf3832b6384756c3ce41"}]}
