)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"549b5e82fd71079b4805a8522450aef3cefd8eca","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"3ac65cf7_e0551731","updated":"2024-04-30 08:51:34.000000000","message":"my last comment was dumb: it\u0027s the response *body* that is causing the func tests to fail, not the headers, so the tests will need to be modified.","commit_id":"9f34f6acb2dd44a362947821b16f9e3ce20b6d9a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1b737f91090aa8e6dcfb77c0bda17ea1e27c3cdf","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"631ce9c5_1a26d15a","updated":"2024-09-16 18:14:46.000000000","message":"@Tim added some more error handling in the complete upload path and test coverage","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"4098e98d_b7096302","updated":"2024-10-01 00:47:27.000000000","message":"LGTM -- some other odd thoughts as I was going through it, but nothing terribly concerning.","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"4dadd5d15ed64ff9ec2c34038fc3b6b92832b4a2","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"3171c3ff_75402dc7","updated":"2024-10-01 13:15:17.000000000","message":"fixes: https://review.opendev.org/c/openstack/swift/+/931011 mpu: minor middleware fixes","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"}],"swift/common/middleware/mpu.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"74ca31cc9d50b33cd283a55dedb716ec2e725def","unresolved":true,"context_lines":[{"line_number":498,"context_line":"                body \u003d b\u0027\u0027.join(body_chunks)"},{"line_number":499,"context_line":"                body_dict \u003d json.loads(body)"},{"line_number":500,"context_line":"                if body_dict.get(\u0027Response Status\u0027) \u003d\u003d \u0027201 Created\u0027:"},{"line_number":501,"context_line":"                    # TODO: repeat check that session has not been aborted"},{"line_number":502,"context_line":"                    # create symlink to manifest"},{"line_number":503,"context_line":"                    manifest_etag \u003d body_dict.get(\u0027Manifest Etag\u0027)"},{"line_number":504,"context_line":"                    mpu_req.headers[TGT_ETAG_SYMLINK_HDR] \u003d manifest_etag"}],"source_content_type":"text/x-python","patch_set":6,"id":"a0b243c5_7d439886","line":501,"updated":"2024-09-11 20:15:04.000000000","message":"What should we do if it has? We\u0027ve already written the manifest -- do we just delete it, or do we need to try to clean up the segments, too?","commit_id":"e554b06ea7ff995b18d7bc4338901dacaddfd1ca"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"5819761a36a59e0e4c5d74a780b9fc7ad7f89ad5","unresolved":true,"context_lines":[{"line_number":498,"context_line":"                body \u003d b\u0027\u0027.join(body_chunks)"},{"line_number":499,"context_line":"                body_dict \u003d json.loads(body)"},{"line_number":500,"context_line":"                if body_dict.get(\u0027Response Status\u0027) \u003d\u003d \u0027201 Created\u0027:"},{"line_number":501,"context_line":"                    # TODO: repeat check that session has not been aborted"},{"line_number":502,"context_line":"                    # create symlink to manifest"},{"line_number":503,"context_line":"                    manifest_etag \u003d body_dict.get(\u0027Manifest Etag\u0027)"},{"line_number":504,"context_line":"                    mpu_req.headers[TGT_ETAG_SYMLINK_HDR] \u003d manifest_etag"}],"source_content_type":"text/x-python","patch_set":6,"id":"a6ee957a_17d52919","line":501,"in_reply_to":"a0b243c5_7d439886","updated":"2024-09-16 18:14:12.000000000","message":"updated the TODO: we have a choice: \n\n* return 409 and stop, leave the auditor to clean up aborted MPU (necessary feature anyway)\n\n* continue, leave the auditor to discover the completed MPU (necessary feature anyway)","commit_id":"e554b06ea7ff995b18d7bc4338901dacaddfd1ca"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"94b7b7a5d590e992e17258f2efe756c53110a3d4","unresolved":false,"context_lines":[{"line_number":498,"context_line":"                body \u003d b\u0027\u0027.join(body_chunks)"},{"line_number":499,"context_line":"                body_dict \u003d json.loads(body)"},{"line_number":500,"context_line":"                if body_dict.get(\u0027Response Status\u0027) \u003d\u003d \u0027201 Created\u0027:"},{"line_number":501,"context_line":"                    # TODO: repeat check that session has not been aborted"},{"line_number":502,"context_line":"                    # create symlink to manifest"},{"line_number":503,"context_line":"                    manifest_etag \u003d body_dict.get(\u0027Manifest Etag\u0027)"},{"line_number":504,"context_line":"                    mpu_req.headers[TGT_ETAG_SYMLINK_HDR] \u003d manifest_etag"}],"source_content_type":"text/x-python","patch_set":6,"id":"4f485abc_d0e5ca06","line":501,"in_reply_to":"a6ee957a_17d52919","updated":"2024-09-16 19:24:30.000000000","message":"Acknowledged","commit_id":"e554b06ea7ff995b18d7bc4338901dacaddfd1ca"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"74ca31cc9d50b33cd283a55dedb716ec2e725def","unresolved":true,"context_lines":[{"line_number":508,"context_line":"                    else:"},{"line_number":509,"context_line":"                        # TODO: test coverage for this condition"},{"line_number":510,"context_line":"                        yield json.dumps("},{"line_number":511,"context_line":"                            {\u0027Response Status\u0027: \u0027501\u0027,"},{"line_number":512,"context_line":"                             \u0027Errors\u0027: ["},{"line_number":513,"context_line":"                                 \u0027Symlink PUT failed: %s\u0027 % mpu_resp.body]}"},{"line_number":514,"context_line":"                        ).encode(\u0027ascii\u0027)"}],"source_content_type":"text/x-python","patch_set":6,"id":"d9daf745_d1705ad6","line":511,"range":{"start_line":511,"start_character":49,"end_line":511,"end_character":52},"updated":"2024-09-11 20:15:04.000000000","message":"Not 500?","commit_id":"e554b06ea7ff995b18d7bc4338901dacaddfd1ca"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"94b7b7a5d590e992e17258f2efe756c53110a3d4","unresolved":false,"context_lines":[{"line_number":508,"context_line":"                    else:"},{"line_number":509,"context_line":"                        # TODO: test coverage for this condition"},{"line_number":510,"context_line":"                        yield json.dumps("},{"line_number":511,"context_line":"                            {\u0027Response Status\u0027: \u0027501\u0027,"},{"line_number":512,"context_line":"                             \u0027Errors\u0027: ["},{"line_number":513,"context_line":"                                 \u0027Symlink PUT failed: %s\u0027 % mpu_resp.body]}"},{"line_number":514,"context_line":"                        ).encode(\u0027ascii\u0027)"}],"source_content_type":"text/x-python","patch_set":6,"id":"29a0ae2f_8844d836","line":511,"range":{"start_line":511,"start_character":49,"end_line":511,"end_character":52},"in_reply_to":"2143ae82_80033946","updated":"2024-09-16 19:24:30.000000000","message":"Done","commit_id":"e554b06ea7ff995b18d7bc4338901dacaddfd1ca"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"5819761a36a59e0e4c5d74a780b9fc7ad7f89ad5","unresolved":true,"context_lines":[{"line_number":508,"context_line":"                    else:"},{"line_number":509,"context_line":"                        # TODO: test coverage for this condition"},{"line_number":510,"context_line":"                        yield json.dumps("},{"line_number":511,"context_line":"                            {\u0027Response Status\u0027: \u0027501\u0027,"},{"line_number":512,"context_line":"                             \u0027Errors\u0027: ["},{"line_number":513,"context_line":"                                 \u0027Symlink PUT failed: %s\u0027 % mpu_resp.body]}"},{"line_number":514,"context_line":"                        ).encode(\u0027ascii\u0027)"}],"source_content_type":"text/x-python","patch_set":6,"id":"2143ae82_80033946","line":511,"range":{"start_line":511,"start_character":49,"end_line":511,"end_character":52},"in_reply_to":"d9daf745_d1705ad6","updated":"2024-09-16 18:14:12.000000000","message":"huh, 501 is a typo, but maybe 503 to the client?","commit_id":"e554b06ea7ff995b18d7bc4338901dacaddfd1ca"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"94b7b7a5d590e992e17258f2efe756c53110a3d4","unresolved":true,"context_lines":[{"line_number":470,"context_line":"            if not errors:"},{"line_number":471,"context_line":"                part_path \u003d \u0027/\u0027.join(["},{"line_number":472,"context_line":"                    self.parts_container, self.reserved_obj, self.upload_id,"},{"line_number":473,"context_line":"                    str(part_number)])"},{"line_number":474,"context_line":"                parsed_manifest.append({"},{"line_number":475,"context_line":"                    \u0027path\u0027: wsgi_to_str(part_path),"},{"line_number":476,"context_line":"                    \u0027etag\u0027: etag})"}],"source_content_type":"text/x-python","patch_set":7,"id":"82e5f11f_bb5d219a","line":473,"range":{"start_line":473,"start_character":20,"end_line":473,"end_character":36},"updated":"2024-09-16 19:24:30.000000000","message":"Off-topic: I wonder if we should zero-pad these... I\u0027d think 6 digits ought to be enough?","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":false,"context_lines":[{"line_number":470,"context_line":"            if not errors:"},{"line_number":471,"context_line":"                part_path \u003d \u0027/\u0027.join(["},{"line_number":472,"context_line":"                    self.parts_container, self.reserved_obj, self.upload_id,"},{"line_number":473,"context_line":"                    str(part_number)])"},{"line_number":474,"context_line":"                parsed_manifest.append({"},{"line_number":475,"context_line":"                    \u0027path\u0027: wsgi_to_str(part_path),"},{"line_number":476,"context_line":"                    \u0027etag\u0027: etag})"}],"source_content_type":"text/x-python","patch_set":7,"id":"66d0d0f8_2938223c","line":473,"range":{"start_line":473,"start_character":20,"end_line":473,"end_character":36},"in_reply_to":"5e0c06f1_19a9e470","updated":"2024-10-01 00:47:27.000000000","message":"Done","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e998bc24aab2934834791c0a087be883a1d54fef","unresolved":true,"context_lines":[{"line_number":470,"context_line":"            if not errors:"},{"line_number":471,"context_line":"                part_path \u003d \u0027/\u0027.join(["},{"line_number":472,"context_line":"                    self.parts_container, self.reserved_obj, self.upload_id,"},{"line_number":473,"context_line":"                    str(part_number)])"},{"line_number":474,"context_line":"                parsed_manifest.append({"},{"line_number":475,"context_line":"                    \u0027path\u0027: wsgi_to_str(part_path),"},{"line_number":476,"context_line":"                    \u0027etag\u0027: etag})"}],"source_content_type":"text/x-python","patch_set":7,"id":"5e0c06f1_19a9e470","line":473,"range":{"start_line":473,"start_character":20,"end_line":473,"end_character":36},"in_reply_to":"7aea17a7_2faf2fb1","updated":"2024-09-27 16:00:07.000000000","message":"done here https://review.opendev.org/c/openstack/swift/+/930741","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"52b2d6fac7fc563583721310e0747a27e3652d12","unresolved":true,"context_lines":[{"line_number":470,"context_line":"            if not errors:"},{"line_number":471,"context_line":"                part_path \u003d \u0027/\u0027.join(["},{"line_number":472,"context_line":"                    self.parts_container, self.reserved_obj, self.upload_id,"},{"line_number":473,"context_line":"                    str(part_number)])"},{"line_number":474,"context_line":"                parsed_manifest.append({"},{"line_number":475,"context_line":"                    \u0027path\u0027: wsgi_to_str(part_path),"},{"line_number":476,"context_line":"                    \u0027etag\u0027: etag})"}],"source_content_type":"text/x-python","patch_set":7,"id":"7aea17a7_2faf2fb1","line":473,"range":{"start_line":473,"start_character":20,"end_line":473,"end_character":36},"in_reply_to":"82e5f11f_bb5d219a","updated":"2024-09-17 19:23:02.000000000","message":"good idea - will follow up in another patch","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"94b7b7a5d590e992e17258f2efe756c53110a3d4","unresolved":true,"context_lines":[{"line_number":519,"context_line":"                    #   return 409, and leave things for the auditor to clean"},{"line_number":520,"context_line":"                    #   up. Alternatively, don\u0027t check - assume we\u0027ll complete"},{"line_number":521,"context_line":"                    #   the symlink before the auditor handles the aborted"},{"line_number":522,"context_line":"                    #   session create symlink to manifest"},{"line_number":523,"context_line":"                    manifest_etag \u003d body_dict.get(\u0027Manifest Etag\u0027)"},{"line_number":524,"context_line":"                    mpu_req.headers[TGT_ETAG_SYMLINK_HDR] \u003d manifest_etag"},{"line_number":525,"context_line":"                    mpu_resp \u003d mpu_req.get_response(self.app)"}],"source_content_type":"text/x-python","patch_set":7,"id":"f63f9aef_2555b1e0","line":522,"range":{"start_line":522,"start_character":32,"end_line":522,"end_character":58},"updated":"2024-09-16 19:24:30.000000000","message":"Was this part supposed to be on its own line, separate from the TODO?","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":false,"context_lines":[{"line_number":519,"context_line":"                    #   return 409, and leave things for the auditor to clean"},{"line_number":520,"context_line":"                    #   up. Alternatively, don\u0027t check - assume we\u0027ll complete"},{"line_number":521,"context_line":"                    #   the symlink before the auditor handles the aborted"},{"line_number":522,"context_line":"                    #   session create symlink to manifest"},{"line_number":523,"context_line":"                    manifest_etag \u003d body_dict.get(\u0027Manifest Etag\u0027)"},{"line_number":524,"context_line":"                    mpu_req.headers[TGT_ETAG_SYMLINK_HDR] \u003d manifest_etag"},{"line_number":525,"context_line":"                    mpu_resp \u003d mpu_req.get_response(self.app)"}],"source_content_type":"text/x-python","patch_set":7,"id":"ef0eb8f5_9e000cb9","line":522,"range":{"start_line":522,"start_character":32,"end_line":522,"end_character":58},"in_reply_to":"d5158cfd_a0caeb18","updated":"2024-10-01 00:47:27.000000000","message":"Done","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"52b2d6fac7fc563583721310e0747a27e3652d12","unresolved":true,"context_lines":[{"line_number":519,"context_line":"                    #   return 409, and leave things for the auditor to clean"},{"line_number":520,"context_line":"                    #   up. Alternatively, don\u0027t check - assume we\u0027ll complete"},{"line_number":521,"context_line":"                    #   the symlink before the auditor handles the aborted"},{"line_number":522,"context_line":"                    #   session create symlink to manifest"},{"line_number":523,"context_line":"                    manifest_etag \u003d body_dict.get(\u0027Manifest Etag\u0027)"},{"line_number":524,"context_line":"                    mpu_req.headers[TGT_ETAG_SYMLINK_HDR] \u003d manifest_etag"},{"line_number":525,"context_line":"                    mpu_resp \u003d mpu_req.get_response(self.app)"}],"source_content_type":"text/x-python","patch_set":7,"id":"d5158cfd_a0caeb18","line":522,"range":{"start_line":522,"start_character":32,"end_line":522,"end_character":58},"in_reply_to":"f63f9aef_2555b1e0","updated":"2024-09-17 19:23:02.000000000","message":"argh, yeah my line wrapper has gobbled it into the paragraph. good catch!","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"94b7b7a5d590e992e17258f2efe756c53110a3d4","unresolved":true,"context_lines":[{"line_number":526,"context_line":"                    if mpu_resp.status_int \u003d\u003d 201:"},{"line_number":527,"context_line":"                        yield body"},{"line_number":528,"context_line":"                        # clean up the multipart-upload record"},{"line_number":529,"context_line":"                        # TODO: move _delete_session before the yield??"},{"line_number":530,"context_line":"                        self._delete_session()"},{"line_number":531,"context_line":"                    else:"},{"line_number":532,"context_line":"                        yield json.dumps("}],"source_content_type":"text/x-python","patch_set":7,"id":"3f4aa182_721324ab","line":529,"updated":"2024-09-16 19:24:30.000000000","message":"What are the pros/cons? It\u0027s not obvious to me which way it should be...","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"48c28e939b2519d8edbddae62481fb6f1e6319f9","unresolved":false,"context_lines":[{"line_number":526,"context_line":"                    if mpu_resp.status_int \u003d\u003d 201:"},{"line_number":527,"context_line":"                        yield body"},{"line_number":528,"context_line":"                        # clean up the multipart-upload record"},{"line_number":529,"context_line":"                        # TODO: move _delete_session before the yield??"},{"line_number":530,"context_line":"                        self._delete_session()"},{"line_number":531,"context_line":"                    else:"},{"line_number":532,"context_line":"                        yield json.dumps("}],"source_content_type":"text/x-python","patch_set":7,"id":"ecd46354_9def5863","line":529,"in_reply_to":"1b045b96_1aeefd0d","updated":"2024-10-01 13:10:39.000000000","message":"Done","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"52b2d6fac7fc563583721310e0747a27e3652d12","unresolved":true,"context_lines":[{"line_number":526,"context_line":"                    if mpu_resp.status_int \u003d\u003d 201:"},{"line_number":527,"context_line":"                        yield body"},{"line_number":528,"context_line":"                        # clean up the multipart-upload record"},{"line_number":529,"context_line":"                        # TODO: move _delete_session before the yield??"},{"line_number":530,"context_line":"                        self._delete_session()"},{"line_number":531,"context_line":"                    else:"},{"line_number":532,"context_line":"                        yield json.dumps("}],"source_content_type":"text/x-python","patch_set":7,"id":"1b045b96_1aeefd0d","line":529,"in_reply_to":"3f4aa182_721324ab","updated":"2024-09-17 19:23:02.000000000","message":"I\u0027ll add some to the comment, but zooming out slightly...\n\nA concurrent abortUpload may occur before the completeUpload operation has created a symlink to manifest. Therefore the abortUpload only deletes the session and writes an abort-marker for the auditor to find. The abort doesn\u0027t synchronously delete any parts or manifest. \n\nWhen the auditor finds an abort marker it needs to check that there is no linked object before deleting manifest and parts, and the auditor will also therefore need to wait a (yet to be implemented) period before doing so to allow for any concurrent completeUpload to finish.\n\nSo there is some advantage in having the completeUpload remove the session ASAP in order to narrow the window for a concurrent abort, and avoid auditor work.","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"94b7b7a5d590e992e17258f2efe756c53110a3d4","unresolved":true,"context_lines":[{"line_number":539,"context_line":"                    yield json.dumps(resp_dict).encode(\u0027ascii\u0027)"},{"line_number":540,"context_line":"                else:"},{"line_number":541,"context_line":"                    resp_dict \u003d {\u0027Response Status\u0027: response_status}"},{"line_number":542,"context_line":"                    yield json.dumps(resp_dict).encode(\u0027ascii\u0027)"},{"line_number":543,"context_line":"            else:"},{"line_number":544,"context_line":"                yield put_resp.body"},{"line_number":545,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"63377e87_74579ce5","line":542,"updated":"2024-09-16 19:24:30.000000000","message":"Why rewrite the response dict? If we\u0027re going to do that, I think we should at least log (probably at debug) the dict we got out of SLO, or we\u0027re going to be miserable trying to figure out what happened.","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e998bc24aab2934834791c0a087be883a1d54fef","unresolved":false,"context_lines":[{"line_number":539,"context_line":"                    yield json.dumps(resp_dict).encode(\u0027ascii\u0027)"},{"line_number":540,"context_line":"                else:"},{"line_number":541,"context_line":"                    resp_dict \u003d {\u0027Response Status\u0027: response_status}"},{"line_number":542,"context_line":"                    yield json.dumps(resp_dict).encode(\u0027ascii\u0027)"},{"line_number":543,"context_line":"            else:"},{"line_number":544,"context_line":"                yield put_resp.body"},{"line_number":545,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"26c2766a_5c626b51","line":542,"in_reply_to":"17120694_bc1f6341","updated":"2024-09-27 16:00:07.000000000","message":"Done","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"52b2d6fac7fc563583721310e0747a27e3652d12","unresolved":true,"context_lines":[{"line_number":539,"context_line":"                    yield json.dumps(resp_dict).encode(\u0027ascii\u0027)"},{"line_number":540,"context_line":"                else:"},{"line_number":541,"context_line":"                    resp_dict \u003d {\u0027Response Status\u0027: response_status}"},{"line_number":542,"context_line":"                    yield json.dumps(resp_dict).encode(\u0027ascii\u0027)"},{"line_number":543,"context_line":"            else:"},{"line_number":544,"context_line":"                yield put_resp.body"},{"line_number":545,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"17120694_bc1f6341","line":542,"in_reply_to":"63377e87_74579ce5","updated":"2024-09-17 19:23:02.000000000","message":"good point. I\u0027ve confused this with when the symlink put fails","commit_id":"edb88792a813aff363704f17b12910542ae64b9c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":true,"context_lines":[{"line_number":42,"context_line":"MPU_SWIFT_SOURCE \u003d \u0027MPU\u0027"},{"line_number":43,"context_line":"MPU_SYSMETA_PREFIX \u003d \u0027x-object-sysmeta-mpu-\u0027"},{"line_number":44,"context_line":"MPU_TRANSIENT_SYSMETA_PREFIX \u003d \u0027x-object-transient-sysmeta-mpu-\u0027"},{"line_number":45,"context_line":"# TODO: application/directory is used in s3api but why?"},{"line_number":46,"context_line":"MPU_CONTENT_TYPE \u003d \u0027application/x-mpu\u0027"},{"line_number":47,"context_line":"MPU_ABORTED_CONTENT_TYPE \u003d \u0027application/x-mpu-aborted\u0027"},{"line_number":48,"context_line":"MPU_MARKER_CONTENT_TYPE \u003d \u0027application/x-mpu-marker\u0027"}],"source_content_type":"text/x-python","patch_set":10,"id":"1152a106_6bd0c66f","line":45,"updated":"2024-10-01 00:47:27.000000000","message":"I forget if I\u0027d mentioned this already elsewhere, but it was for ProxyFS compatibility. Since we had a listing like\n\n```\n\u003cobj\u003e/\u003cupload-id\u003e\n\u003cobj\u003e/\u003cupload-id\u003e/1\n\u003cobj\u003e/\u003cupload-id\u003e/2\n\u003cobj\u003e/\u003cupload-id\u003e/3\n...\n```\n\nProxyFS needed the `application/directory` content-type or it wouldn\u0027t *treat it* like a directory, and all the segment uploads would fail with some translated `ENOTDIR`.\n\nI wonder if we could get rid of the whole `HAS_USER_CONTENT_TYPE_KEY`/`USER_CONTENT_TYPE_KEY` hack for this...","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":true,"context_lines":[{"line_number":206,"context_line":"        self._authorize_request(\u0027write_acl\u0027)"},{"line_number":207,"context_line":""},{"line_number":208,"context_line":"    def make_relative_path(self, *parts):"},{"line_number":209,"context_line":"        return \u0027/\u0027.join([str(p) for p in parts])"},{"line_number":210,"context_line":""},{"line_number":211,"context_line":"    def make_path(self, *parts):"},{"line_number":212,"context_line":"        return \u0027/\u0027.join("}],"source_content_type":"text/x-python","patch_set":10,"id":"51db6bce_c6ab480c","line":209,"updated":"2024-10-01 00:47:27.000000000","message":"nit: Could drop the `[]`s","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"48c28e939b2519d8edbddae62481fb6f1e6319f9","unresolved":false,"context_lines":[{"line_number":206,"context_line":"        self._authorize_request(\u0027write_acl\u0027)"},{"line_number":207,"context_line":""},{"line_number":208,"context_line":"    def make_relative_path(self, *parts):"},{"line_number":209,"context_line":"        return \u0027/\u0027.join([str(p) for p in parts])"},{"line_number":210,"context_line":""},{"line_number":211,"context_line":"    def make_path(self, *parts):"},{"line_number":212,"context_line":"        return \u0027/\u0027.join("}],"source_content_type":"text/x-python","patch_set":10,"id":"d1c540c1_441c37ca","line":209,"in_reply_to":"51db6bce_c6ab480c","updated":"2024-10-01 13:10:39.000000000","message":"Done","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":true,"context_lines":[{"line_number":345,"context_line":"        # looking at the manifest that\u0027s about to be written."},{"line_number":346,"context_line":"        errors \u003d []"},{"line_number":347,"context_line":"        for item in slo_manifest[:-1]:"},{"line_number":348,"context_line":"            if not item:"},{"line_number":349,"context_line":"                continue"},{"line_number":350,"context_line":"            self.total_bytes +\u003d item[\u0027bytes\u0027]"},{"line_number":351,"context_line":"            if item[\u0027bytes\u0027] \u003c self.mw.min_part_size:"},{"line_number":352,"context_line":"                # TODO: add tests coverage"}],"source_content_type":"text/x-python","patch_set":10,"id":"2a3957aa_c6dd85a1","line":349,"range":{"start_line":348,"start_character":12,"end_line":349,"end_character":24},"updated":"2024-10-01 00:47:27.000000000","message":"When would this be false-y?","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"48c28e939b2519d8edbddae62481fb6f1e6319f9","unresolved":false,"context_lines":[{"line_number":345,"context_line":"        # looking at the manifest that\u0027s about to be written."},{"line_number":346,"context_line":"        errors \u003d []"},{"line_number":347,"context_line":"        for item in slo_manifest[:-1]:"},{"line_number":348,"context_line":"            if not item:"},{"line_number":349,"context_line":"                continue"},{"line_number":350,"context_line":"            self.total_bytes +\u003d item[\u0027bytes\u0027]"},{"line_number":351,"context_line":"            if item[\u0027bytes\u0027] \u003c self.mw.min_part_size:"},{"line_number":352,"context_line":"                # TODO: add tests coverage"}],"source_content_type":"text/x-python","patch_set":10,"id":"49921c2b_49cdc371","line":349,"range":{"start_line":348,"start_character":12,"end_line":349,"end_character":24},"in_reply_to":"2a3957aa_c6dd85a1","updated":"2024-10-01 13:10:39.000000000","message":"IIUC when slo fails to find a segment https://stackoverflow.com/a/69517534\n\ns3 multi_upload.py has a similar check https://github.com/openstack/swift/blob/46e7da97c6e620ba2998872901ed44055714e699/swift/common/middleware/s3api/controllers/multi_upload.py#L772-L775","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":false,"context_lines":[{"line_number":351,"context_line":"            if item[\u0027bytes\u0027] \u003c self.mw.min_part_size:"},{"line_number":352,"context_line":"                # TODO: add tests coverage"},{"line_number":353,"context_line":"                errors.append((item[\u0027name\u0027], self.too_small_message))"},{"line_number":354,"context_line":"        self.total_bytes +\u003d slo_manifest[-1][\u0027bytes\u0027]"},{"line_number":355,"context_line":"        return errors"},{"line_number":356,"context_line":""},{"line_number":357,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"7f2ac246_ea494558","line":354,"range":{"start_line":354,"start_character":28,"end_line":354,"end_character":44},"updated":"2024-10-01 00:47:27.000000000","message":"Can we have an MPU upload with zero parts? \u0027Cause this\u0027d `IndexError` if we can.\n\nOh, nevermind -- this gets addressed in https://review.opendev.org/c/openstack/swift/+/930741","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":true,"context_lines":[{"line_number":543,"context_line":"            \u0027Accept\u0027: \u0027application/json\u0027,"},{"line_number":544,"context_line":"            MPU_SYSMETA_ETAG_KEY: mpu_etag,"},{"line_number":545,"context_line":"            MPU_PARTS_COUNT_KEY: len(manifest),"},{"line_number":546,"context_line":"            # TODO: include max part index in sysmeta to detect \"pure\" manifest"},{"line_number":547,"context_line":"        }"},{"line_number":548,"context_line":"        manifest_headers.update(self.session.get_manifest_headers())"},{"line_number":549,"context_line":"        # append the MPU etag to any existing container override sysmeta for"}],"source_content_type":"text/x-python","patch_set":10,"id":"38585d61_87071dbb","line":546,"range":{"start_line":546,"start_character":64,"end_line":546,"end_character":79},"updated":"2024-10-01 00:47:27.000000000","message":"I\u0027m not sure what this means -- is that a manifest with no backing segments?","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"48c28e939b2519d8edbddae62481fb6f1e6319f9","unresolved":false,"context_lines":[{"line_number":543,"context_line":"            \u0027Accept\u0027: \u0027application/json\u0027,"},{"line_number":544,"context_line":"            MPU_SYSMETA_ETAG_KEY: mpu_etag,"},{"line_number":545,"context_line":"            MPU_PARTS_COUNT_KEY: len(manifest),"},{"line_number":546,"context_line":"            # TODO: include max part index in sysmeta to detect \"pure\" manifest"},{"line_number":547,"context_line":"        }"},{"line_number":548,"context_line":"        manifest_headers.update(self.session.get_manifest_headers())"},{"line_number":549,"context_line":"        # append the MPU etag to any existing container override sysmeta for"}],"source_content_type":"text/x-python","patch_set":10,"id":"131221f0_117675bf","line":546,"range":{"start_line":546,"start_character":64,"end_line":546,"end_character":79},"in_reply_to":"38585d61_87071dbb","updated":"2024-10-01 13:10:39.000000000","message":"my personal vernacular, sorry! I think of a manifest whose parts increment uniformly by 1 from 1 as \"pure\" - it is possible to infer the part path from the part_number param given in a GET/HEAD without looking up the manifest.\n\nI had this notion of optimisations when a mpu is known to be pure and a part_number HEAD request is being handled, but on reflection I\u0027m not seeing it now.\n\nI\u0027ll at least make the comment less mysterious","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":true,"context_lines":[{"line_number":546,"context_line":"            # TODO: include max part index in sysmeta to detect \"pure\" manifest"},{"line_number":547,"context_line":"        }"},{"line_number":548,"context_line":"        manifest_headers.update(self.session.get_manifest_headers())"},{"line_number":549,"context_line":"        # append the MPU etag to any existing container override sysmeta for"},{"line_number":550,"context_line":"        # the manifest; this will be forwarded to the user container"},{"line_number":551,"context_line":"        update_etag_override_header("},{"line_number":552,"context_line":"            manifest_headers, mpu_etag, [(\u0027mpu_etag\u0027, mpu_etag)])"}],"source_content_type":"text/x-python","patch_set":10,"id":"2d5d21fa_f8062184","line":549,"range":{"start_line":549,"start_character":10,"end_line":549,"end_character":16},"updated":"2024-10-01 00:47:27.000000000","message":"Pretty sure we\u0027re setting the override sysmeta, not appending to it.","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"48c28e939b2519d8edbddae62481fb6f1e6319f9","unresolved":false,"context_lines":[{"line_number":546,"context_line":"            # TODO: include max part index in sysmeta to detect \"pure\" manifest"},{"line_number":547,"context_line":"        }"},{"line_number":548,"context_line":"        manifest_headers.update(self.session.get_manifest_headers())"},{"line_number":549,"context_line":"        # append the MPU etag to any existing container override sysmeta for"},{"line_number":550,"context_line":"        # the manifest; this will be forwarded to the user container"},{"line_number":551,"context_line":"        update_etag_override_header("},{"line_number":552,"context_line":"            manifest_headers, mpu_etag, [(\u0027mpu_etag\u0027, mpu_etag)])"}],"source_content_type":"text/x-python","patch_set":10,"id":"98b07235_5d711171","line":549,"range":{"start_line":549,"start_character":10,"end_line":549,"end_character":16},"in_reply_to":"2d5d21fa_f8062184","updated":"2024-10-01 13:10:39.000000000","message":"agree. what was I thinking? manifest_headers is just client-originated metadata. Did I mean to respect any existing etag override on the current completeUpload request? Given that completeUpload is a POST to an object url it would be weird for another middleware to have set an etag override. But anyway, it\u0027d make more sense to respect that for the symlink PUT. hmmm.\n\nwill change the comment","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":true,"context_lines":[{"line_number":557,"context_line":"            params\u003d{\u0027multipart-manifest\u0027: \u0027put\u0027, \u0027heartbeat\u0027: \u0027on\u0027})"},{"line_number":558,"context_line":"        slo_callback_handler \u003d MPUSloCallbackHandler(self.mw)"},{"line_number":559,"context_line":"        manifest_req.environ[\u0027swift.callback.slo_manifest_hook\u0027] \u003d \\"},{"line_number":560,"context_line":"            slo_callback_handler.part_size_checker"},{"line_number":561,"context_line":"        return manifest_req.get_response(self.app), slo_callback_handler"},{"line_number":562,"context_line":""},{"line_number":563,"context_line":"    def _put_symlink(self, mpu_etag, mpu_bytes):"}],"source_content_type":"text/x-python","patch_set":10,"id":"1f15a594_e26a3f0c","line":560,"range":{"start_line":560,"start_character":33,"end_line":560,"end_character":50},"updated":"2024-10-01 00:47:27.000000000","message":"Alternatively, we could rename this to be `__call__` in `MPUSloCallbackHandler`. 🤷","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"48c28e939b2519d8edbddae62481fb6f1e6319f9","unresolved":false,"context_lines":[{"line_number":557,"context_line":"            params\u003d{\u0027multipart-manifest\u0027: \u0027put\u0027, \u0027heartbeat\u0027: \u0027on\u0027})"},{"line_number":558,"context_line":"        slo_callback_handler \u003d MPUSloCallbackHandler(self.mw)"},{"line_number":559,"context_line":"        manifest_req.environ[\u0027swift.callback.slo_manifest_hook\u0027] \u003d \\"},{"line_number":560,"context_line":"            slo_callback_handler.part_size_checker"},{"line_number":561,"context_line":"        return manifest_req.get_response(self.app), slo_callback_handler"},{"line_number":562,"context_line":""},{"line_number":563,"context_line":"    def _put_symlink(self, mpu_etag, mpu_bytes):"}],"source_content_type":"text/x-python","patch_set":10,"id":"4927f0c1_3a46f077","line":560,"range":{"start_line":560,"start_character":33,"end_line":560,"end_character":50},"in_reply_to":"1f15a594_e26a3f0c","updated":"2024-10-01 13:10:39.000000000","message":"💯","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":true,"context_lines":[{"line_number":566,"context_line":"        mpu_headers \u003d {"},{"line_number":567,"context_line":"            ALLOW_RESERVED_NAMES: \u0027true\u0027,"},{"line_number":568,"context_line":"            MPU_UPLOAD_ID_KEY: self.upload_id,"},{"line_number":569,"context_line":"            \u0027X-Timestamp\u0027: self.session.created_timestamp.internal,"},{"line_number":570,"context_line":"            TGT_OBJ_SYMLINK_HDR: self.manifest_relative_path,"},{"line_number":571,"context_line":"            \u0027Content-Length\u0027: \u00270\u0027,"},{"line_number":572,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":10,"id":"2898f8d3_1cc8bec4","line":569,"updated":"2024-10-01 00:47:27.000000000","message":"Maybe this should go in `get_symlink_headers()`?","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"48c28e939b2519d8edbddae62481fb6f1e6319f9","unresolved":false,"context_lines":[{"line_number":566,"context_line":"        mpu_headers \u003d {"},{"line_number":567,"context_line":"            ALLOW_RESERVED_NAMES: \u0027true\u0027,"},{"line_number":568,"context_line":"            MPU_UPLOAD_ID_KEY: self.upload_id,"},{"line_number":569,"context_line":"            \u0027X-Timestamp\u0027: self.session.created_timestamp.internal,"},{"line_number":570,"context_line":"            TGT_OBJ_SYMLINK_HDR: self.manifest_relative_path,"},{"line_number":571,"context_line":"            \u0027Content-Length\u0027: \u00270\u0027,"},{"line_number":572,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":10,"id":"abfad41e_0c47b2f3","line":569,"in_reply_to":"2898f8d3_1cc8bec4","updated":"2024-10-01 13:10:39.000000000","message":"it could, but I\u0027d intended those session helpers to manage user-provided headers, and have the mechanics of mpu management live in the middleware handlers.\n\nI\u0027ll rename the methods for now to make it clearer - and also in a later patch revisit the HAS_USER_CONTENT_TYPE complexity","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":true,"context_lines":[{"line_number":578,"context_line":"            path\u003dmpu_path, method\u003d\u0027PUT\u0027, headers\u003dmpu_headers)"},{"line_number":579,"context_line":"        mpu_resp \u003d mpu_req.get_response(self.app)"},{"line_number":580,"context_line":"        drain_and_close(mpu_resp)"},{"line_number":581,"context_line":"        return mpu_resp"},{"line_number":582,"context_line":""},{"line_number":583,"context_line":"    def _make_complete_upload_resp_iter(self, manifest, mpu_etag):"},{"line_number":584,"context_line":"        def response_iter():"}],"source_content_type":"text/x-python","patch_set":10,"id":"2313730a_0bc13f5a","line":581,"updated":"2024-10-01 00:47:27.000000000","message":"It\u0027s a little funny to me that we drain-and-close in here, but still pass the whole response out. It looks like we could maybe just pass the status?\n\nOr we pass the whole response, so we can log the body if we got an unexpected status.","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"48c28e939b2519d8edbddae62481fb6f1e6319f9","unresolved":false,"context_lines":[{"line_number":578,"context_line":"            path\u003dmpu_path, method\u003d\u0027PUT\u0027, headers\u003dmpu_headers)"},{"line_number":579,"context_line":"        mpu_resp \u003d mpu_req.get_response(self.app)"},{"line_number":580,"context_line":"        drain_and_close(mpu_resp)"},{"line_number":581,"context_line":"        return mpu_resp"},{"line_number":582,"context_line":""},{"line_number":583,"context_line":"    def _make_complete_upload_resp_iter(self, manifest, mpu_etag):"},{"line_number":584,"context_line":"        def response_iter():"}],"source_content_type":"text/x-python","patch_set":10,"id":"d7df9f36_3c51f3f6","line":581,"in_reply_to":"2313730a_0bc13f5a","updated":"2024-10-01 13:10:39.000000000","message":"moved to the call resp iter","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"}],"test/unit/common/test_request_helpers.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b9198e4af5e4d464ccbb92d35f153634a2d30d2f","unresolved":true,"context_lines":[{"line_number":568,"context_line":"        self.assertEqual("},{"line_number":569,"context_line":"            {\u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027:"},{"line_number":570,"context_line":"             \u0027; x\u003d123; y\u003dfoo\u0027},"},{"line_number":571,"context_line":"            headers)"},{"line_number":572,"context_line":""},{"line_number":573,"context_line":""},{"line_number":574,"context_line":"class TestHTTPResponseToDocumentIters(unittest.TestCase):"}],"source_content_type":"text/x-python","patch_set":10,"id":"79b7b344_a0809988","line":571,"updated":"2024-10-01 00:47:27.000000000","message":"Could use some tests where `headers` already has a `\u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027` key.","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"48c28e939b2519d8edbddae62481fb6f1e6319f9","unresolved":false,"context_lines":[{"line_number":568,"context_line":"        self.assertEqual("},{"line_number":569,"context_line":"            {\u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027:"},{"line_number":570,"context_line":"             \u0027; x\u003d123; y\u003dfoo\u0027},"},{"line_number":571,"context_line":"            headers)"},{"line_number":572,"context_line":""},{"line_number":573,"context_line":""},{"line_number":574,"context_line":"class TestHTTPResponseToDocumentIters(unittest.TestCase):"}],"source_content_type":"text/x-python","patch_set":10,"id":"313c34a8_6a9357a3","line":571,"in_reply_to":"79b7b344_a0809988","updated":"2024-10-01 13:10:39.000000000","message":"Acknowledged","commit_id":"18e1b693852488464e68ad05ed355e9bffc6e35c"}]}
