)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"7c07033c3b1d29c5a04933e3d30a2bd4383cfaa4","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"fe23e6e6_348ded6c","updated":"2023-06-27 02:49:23.000000000","message":"ok, this is a good fix worth landing on it\u0027s own - with more refactoring coming down the pipe aftwards\n\nI think we should land what we have that makes sense and keep going","commit_id":"68e48c8684aa6a7f4673b1f8750b06d1e8109ebd"}],"swift/proxy/controllers/base.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"60d4c80b0ade29c36ba921cc02fea5d757160d23","unresolved":true,"context_lines":[{"line_number":1032,"context_line":"    def _get_source_and_node(self):"},{"line_number":1033,"context_line":"        raise NotImplementedError()"},{"line_number":1034,"context_line":""},{"line_number":1035,"context_line":"    def _replace_source_and_node(self, err_msg):"},{"line_number":1036,"context_line":"        # be defensive against _get_source_and_node modifying self.source"},{"line_number":1037,"context_line":"        # or self.node..."},{"line_number":1038,"context_line":"        old_source \u003d self.source"}],"source_content_type":"text/x-python","patch_set":1,"id":"8d69fe95_1b385f5b","line":1035,"updated":"2023-06-23 17:28:33.000000000","message":"there\u0027s scope to apply https://review.opendev.org/c/openstack/swift/+/883878 onto this, I ran out of time to do the rebase etc","commit_id":"594253fe03e19beb8d65c77b5e36e0eb3ef5dc40"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"60d4c80b0ade29c36ba921cc02fea5d757160d23","unresolved":true,"context_lines":[{"line_number":1036,"context_line":"        # be defensive against _get_source_and_node modifying self.source"},{"line_number":1037,"context_line":"        # or self.node..."},{"line_number":1038,"context_line":"        old_source \u003d self.source"},{"line_number":1039,"context_line":"        old_node \u003d self.node"},{"line_number":1040,"context_line":""},{"line_number":1041,"context_line":"        new_source, new_node \u003d self._get_source_and_node()"},{"line_number":1042,"context_line":"        if not new_source:"}],"source_content_type":"text/x-python","patch_set":1,"id":"479f09d7_e1179543","line":1039,"updated":"2023-06-23 17:28:33.000000000","message":"we could fix _get_source_and_node to not mutate the instance attrs, but given the lack of test coverage and existing bugs, it seemed a good idea to be defensive","commit_id":"594253fe03e19beb8d65c77b5e36e0eb3ef5dc40"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"7c07033c3b1d29c5a04933e3d30a2bd4383cfaa4","unresolved":true,"context_lines":[{"line_number":1031,"context_line":"        self.source_parts_iter \u003d None"},{"line_number":1032,"context_line":""},{"line_number":1033,"context_line":"    def _get_source_and_node(self):"},{"line_number":1034,"context_line":"        raise NotImplementedError()"},{"line_number":1035,"context_line":""},{"line_number":1036,"context_line":"    def _replace_source_and_node(self, err_msg):"},{"line_number":1037,"context_line":"        # be defensive against _get_source_and_node modifying self.source"}],"source_content_type":"text/x-python","patch_set":2,"id":"36ffac34_2fdce052","line":1034,"updated":"2023-06-27 02:49:23.000000000","message":"oh nice, explicit abstract interface","commit_id":"68e48c8684aa6a7f4673b1f8750b06d1e8109ebd"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"7c07033c3b1d29c5a04933e3d30a2bd4383cfaa4","unresolved":true,"context_lines":[{"line_number":1540,"context_line":"            # has two versions of the same object, we might end up switching"},{"line_number":1541,"context_line":"            # between old and new mid-stream and giving garbage to the client."},{"line_number":1542,"context_line":"            self.used_source_etag \u003d normalize_etag(src_headers.get(\u0027etag\u0027, \u0027\u0027))"},{"line_number":1543,"context_line":"            self.node \u003d node"},{"line_number":1544,"context_line":"            return source, node"},{"line_number":1545,"context_line":"        return None, None"},{"line_number":1546,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"d1d300e5_d1809931","line":1543,"updated":"2023-06-27 02:49:23.000000000","message":"so the ECFragGetter\u0027s impl maybe doesn\u0027t mutate self.node anymore, but the replicated instance still does - so defensive pattern in the new replace method is what we need.","commit_id":"68e48c8684aa6a7f4673b1f8750b06d1e8109ebd"}],"swift/proxy/controllers/obj.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"60d4c80b0ade29c36ba921cc02fea5d757160d23","unresolved":true,"context_lines":[{"line_number":2786,"context_line":"                node, self.app.recoverable_node_timeout)"},{"line_number":2787,"context_line":""},{"line_number":2788,"context_line":"            if source:"},{"line_number":2789,"context_line":"                self.node \u003d node"},{"line_number":2790,"context_line":"                yield source, node"},{"line_number":2791,"context_line":"            else:"},{"line_number":2792,"context_line":"                yield None, None"}],"source_content_type":"text/x-python","patch_set":1,"id":"01ece129_07101753","side":"PARENT","line":2789,"updated":"2023-06-23 17:28:33.000000000","message":"ok, so I did also fix this one","commit_id":"b8dc7b3d353462adb16911f757918bf55ab99277"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"7c07033c3b1d29c5a04933e3d30a2bd4383cfaa4","unresolved":true,"context_lines":[{"line_number":2786,"context_line":"                node, self.app.recoverable_node_timeout)"},{"line_number":2787,"context_line":""},{"line_number":2788,"context_line":"            if source:"},{"line_number":2789,"context_line":"                self.node \u003d node"},{"line_number":2790,"context_line":"                yield source, node"},{"line_number":2791,"context_line":"            else:"},{"line_number":2792,"context_line":"                yield None, None"}],"source_content_type":"text/x-python","patch_set":1,"id":"5a507c4f_f9ab1955","side":"PARENT","line":2789,"in_reply_to":"01ece129_07101753","updated":"2023-06-27 02:49:23.000000000","message":"oic, so this iterator (used in \"dig_for_\" as the source_and_node_iter property) was mutating the ECFragGetter\u0027s attributes.","commit_id":"b8dc7b3d353462adb16911f757918bf55ab99277"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"7c07033c3b1d29c5a04933e3d30a2bd4383cfaa4","unresolved":true,"context_lines":[{"line_number":2610,"context_line":"                except RangeAlreadyComplete:"},{"line_number":2611,"context_line":"                    break"},{"line_number":2612,"context_line":"                buf \u003d b\u0027\u0027"},{"line_number":2613,"context_line":"                old_node \u003d self.node"},{"line_number":2614,"context_line":"                new_source, new_node \u003d self._dig_for_source_and_node()"},{"line_number":2615,"context_line":"                if new_source:"},{"line_number":2616,"context_line":"                    self.app.error_occurred("}],"source_content_type":"text/x-python","patch_set":2,"id":"0fb60f1d_6760e727","side":"PARENT","line":2613,"updated":"2023-06-27 02:49:23.000000000","message":"i guess this was the only place we were already getting this tricky pattern right?","commit_id":"e290d47c435627082b3825b67e27ea3a3c99f01f"}],"test/unit/proxy/controllers/test_obj.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"7c07033c3b1d29c5a04933e3d30a2bd4383cfaa4","unresolved":true,"context_lines":[{"line_number":1596,"context_line":"            resp \u003d req.get_response(self.app)"},{"line_number":1597,"context_line":"            self.assertEqual(resp.status_int, 200)"},{"line_number":1598,"context_line":"            _ \u003d resp.body"},{"line_number":1599,"context_line":"        self.assertEqual(len(log.requests), 2)"},{"line_number":1600,"context_line":""},{"line_number":1601,"context_line":"        def make_key(r):"},{"line_number":1602,"context_line":"            r[\u0027device\u0027] \u003d r[\u0027path\u0027].split(\u0027/\u0027)[1]"}],"source_content_type":"text/x-python","patch_set":2,"id":"04d80742_7edf9478","line":1599,"updated":"2023-06-27 02:49:23.000000000","message":"ok, so this is a simple replicated case with a single reconnect","commit_id":"68e48c8684aa6a7f4673b1f8750b06d1e8109ebd"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"7c07033c3b1d29c5a04933e3d30a2bd4383cfaa4","unresolved":true,"context_lines":[{"line_number":1603,"context_line":"            return \u0027%(ip)s:%(port)s/%(device)s\u0027 % r"},{"line_number":1604,"context_line":"        # the first node got errors incr\u0027d"},{"line_number":1605,"context_line":"        expected_error_limiting \u003d {"},{"line_number":1606,"context_line":"            make_key(log.requests[0]): {"},{"line_number":1607,"context_line":"                \u0027errors\u0027: 1,"},{"line_number":1608,"context_line":"                \u0027last_error\u0027: mock.ANY,"},{"line_number":1609,"context_line":"            }"}],"source_content_type":"text/x-python","patch_set":2,"id":"7592b8cf_0e2edd41","line":1606,"updated":"2023-06-27 02:49:23.000000000","message":"yup, it\u0027s a bug if we\u0027re error limiting the second node/request\n\n\tE       AssertionError: {\u002710.0.0.1:1001/sdb\u0027: {\u0027errors\u0027: 1, \u0027last_error\u0027: 1687834043.209441}} !\u003d {\u002710.0.0.2:1002/sdc\u0027: {\u0027errors\u0027: 1, \u0027last_error\u0027: \u003cANY\u003e}}\n\tE       - {\u002710.0.0.1:1001/sdb\u0027: {\u0027errors\u0027: 1, \u0027last_error\u0027: 1687834043.209441}}\n\tE       ?          ^    ^   ^                               ^^^^^^^^^^^^^^^^^\n\tE       \n\tE       + {\u002710.0.0.2:1002/sdc\u0027: {\u0027errors\u0027: 1, \u0027last_error\u0027: \u003cANY\u003e}}\n\tE       ?          ^    ^   ^                               ^^^^^","commit_id":"68e48c8684aa6a7f4673b1f8750b06d1e8109ebd"}]}
