)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"b8e06783be625b326334a9a9e790e83abc4c43c8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"18b13234_8d5b6cf3","updated":"2021-10-13 14:44:57.000000000","message":"Does this relate to https://review.opendev.org/c/openstack/swift/+/811247 and if so how?","commit_id":"fd3c3a8eeb1f7d67384d9db8ab6bb0b5c6fcb1f5"},{"author":{"_account_id":17363,"name":"Timur Alperovich","email":"timur@timuralp.com","username":"timuralp"},"change_message_id":"fa41eb24794b16b4bb7a335bce2a4f830c34fe7a","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"ef25a63d_481d0d8c","in_reply_to":"18b13234_8d5b6cf3","updated":"2021-10-14 16:07:18.000000000","message":"This is about listing the in-progress uploads. The prior patch was about listing the parts in a given upload.","commit_id":"fd3c3a8eeb1f7d67384d9db8ab6bb0b5c6fcb1f5"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c01c75e093ab8f385260cf48deb88e39a7cae497","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"0efdc486_b0e504e6","updated":"2021-10-15 15:40:12.000000000","message":"If I understand the multipart parts listings bug correctly the issue was mostly about the ordering of segments 1, 10, 2, 20, 3, 30\n\nThis change seems to be more about skipping over enough segments to find enough of the uploads... \n\n... but I\u0027m worried it\u0027s making a significant number of requests to page through all the segments, that\u0027s a lot of CPU doing [de]serialization sqlite-\u003ejson-\u003ehttp-\u003eproxy and also all that etag decryption just to throw it away.\n\nWish I had a better idea!  (custom code in the container server to do prefix/delim style skip queries that are segment aware!?  might be something to think about for ALO...)\n\nWould some additional test stubs be useful to you?\n\nhttps://review.opendev.org/c/openstack/swift/+/814189","commit_id":"5a7cf2aaa379f6d43eea468ef36b005020ed979c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"5d9e0eacb3fc3c1fc74bd1ad3dc680ffd981480e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"ca8b53ed_d205d4fa","updated":"2022-02-04 07:16:37.000000000","message":"We\u0027ve been running with this in prod for a while. The (potentially many, *many*) extra backend requests aren\u0027t great, but it seems better than returning incorrect results. At least clients can limit results (and as a result, backend requests) with things like key-marker, prefix, and max-uploads.\n\nThis definitely highlights a design limitation to think about if/when we implement a more MPU-like Swift-native large object.","commit_id":"363aa3319eda33af9699916cbc75cf5d779a7352"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"bc5192b3448dd3f3b35beb12723d6415a3b2da44","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"0255afc9_9bb99a25","updated":"2022-02-04 05:34:41.000000000","message":"recheck","commit_id":"363aa3319eda33af9699916cbc75cf5d779a7352"}],"swift/common/middleware/s3api/controllers/multi_upload.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c01c75e093ab8f385260cf48deb88e39a7cae497","unresolved":true,"context_lines":[{"line_number":338,"context_line":""},{"line_number":339,"context_line":"            # uploads is a list consists of dict, {key, upload_id,"},{"line_number":340,"context_line":"            # last_modified} Note that pattern matcher will drop whole segments"},{"line_number":341,"context_line":"            # objects like as object_name/upload_id/1."},{"line_number":342,"context_line":"            pattern \u003d re.compile(\u0027/[0-9]+$\u0027)"},{"line_number":343,"context_line":"            new_uploads \u003d [object_to_upload(obj) for obj in objects if"},{"line_number":344,"context_line":"                           pattern.search(obj.get(\u0027name\u0027, \u0027\u0027)) is None]"}],"source_content_type":"text/x-python","patch_set":2,"id":"403b98de_8bbba23c","line":341,"updated":"2021-10-15 15:40:12.000000000","message":"comment needs updating s/uploads/new_uploads/\n\nalso, I think renameing the regex variable lessons the need for the comment\n\n\tdiff --git a/swift/common/middleware/s3api/controllers/multi_upload.py b/swift/common/middleware/s3api/controllers/multi_upload.py\n\tindex da1feb8a6..3667ff557 100644\n\t--- a/swift/common/middleware/s3api/controllers/multi_upload.py\n\t+++ b/swift/common/middleware/s3api/controllers/multi_upload.py\n\t@@ -325,6 +325,8 @@ class UploadsController(Controller):\n\t\t\t\t \u0027last_modified\u0027: object_info[\u0027last_modified\u0027]}\n\t\t     return obj_dict\n\t \n\t+        is_segment \u003d re.compile(\u0027.*/[0-9]+$\u0027)\n\t+\n\t\t while len(uploads) \u003c maxuploads:\n\t\t     try:\n\t\t\t resp \u003d req.get_response(self.app, container\u003dcontainer,\n\t@@ -336,12 +338,8 @@ class UploadsController(Controller):\n\t\t     if not objects:\n\t\t\t break\n\t \n\t-            # uploads is a list consists of dict, {key, upload_id,\n\t-            # last_modified} Note that pattern matcher will drop whole segments\n\t-            # objects like as object_name/upload_id/1.\n\t-            pattern \u003d re.compile(\u0027/[0-9]+$\u0027)\n\t-            new_uploads \u003d [object_to_upload(obj) for obj in objects if\n\t-                           pattern.search(obj.get(\u0027name\u0027, \u0027\u0027)) is None]\n\t+            new_uploads \u003d [object_to_upload(obj) for obj in objects\n\t+                           if not is_segment.match(obj.get(\u0027name\u0027, \u0027\u0027))]\n\t \n\t\t     new_prefixes \u003d []\n\t\t     if \u0027delimiter\u0027 in req.params:","commit_id":"5a7cf2aaa379f6d43eea468ef36b005020ed979c"},{"author":{"_account_id":17363,"name":"Timur Alperovich","email":"timur@timuralp.com","username":"timuralp"},"change_message_id":"9752ce14eade13855bb0f82094448d781f265382","unresolved":false,"context_lines":[{"line_number":338,"context_line":""},{"line_number":339,"context_line":"            # uploads is a list consists of dict, {key, upload_id,"},{"line_number":340,"context_line":"            # last_modified} Note that pattern matcher will drop whole segments"},{"line_number":341,"context_line":"            # objects like as object_name/upload_id/1."},{"line_number":342,"context_line":"            pattern \u003d re.compile(\u0027/[0-9]+$\u0027)"},{"line_number":343,"context_line":"            new_uploads \u003d [object_to_upload(obj) for obj in objects if"},{"line_number":344,"context_line":"                           pattern.search(obj.get(\u0027name\u0027, \u0027\u0027)) is None]"}],"source_content_type":"text/x-python","patch_set":2,"id":"7959ae7f_48bba297","line":341,"in_reply_to":"403b98de_8bbba23c","updated":"2021-11-17 00:18:26.000000000","message":"Done","commit_id":"5a7cf2aaa379f6d43eea468ef36b005020ed979c"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c01c75e093ab8f385260cf48deb88e39a7cae497","unresolved":true,"context_lines":[{"line_number":339,"context_line":"            # uploads is a list consists of dict, {key, upload_id,"},{"line_number":340,"context_line":"            # last_modified} Note that pattern matcher will drop whole segments"},{"line_number":341,"context_line":"            # objects like as object_name/upload_id/1."},{"line_number":342,"context_line":"            pattern \u003d re.compile(\u0027/[0-9]+$\u0027)"},{"line_number":343,"context_line":"            new_uploads \u003d [object_to_upload(obj) for obj in objects if"},{"line_number":344,"context_line":"                           pattern.search(obj.get(\u0027name\u0027, \u0027\u0027)) is None]"},{"line_number":345,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"8294114c_56aea67c","line":342,"updated":"2021-10-15 15:40:12.000000000","message":"this definition can be moved out of the loop","commit_id":"5a7cf2aaa379f6d43eea468ef36b005020ed979c"},{"author":{"_account_id":17363,"name":"Timur Alperovich","email":"timur@timuralp.com","username":"timuralp"},"change_message_id":"9752ce14eade13855bb0f82094448d781f265382","unresolved":false,"context_lines":[{"line_number":339,"context_line":"            # uploads is a list consists of dict, {key, upload_id,"},{"line_number":340,"context_line":"            # last_modified} Note that pattern matcher will drop whole segments"},{"line_number":341,"context_line":"            # objects like as object_name/upload_id/1."},{"line_number":342,"context_line":"            pattern \u003d re.compile(\u0027/[0-9]+$\u0027)"},{"line_number":343,"context_line":"            new_uploads \u003d [object_to_upload(obj) for obj in objects if"},{"line_number":344,"context_line":"                           pattern.search(obj.get(\u0027name\u0027, \u0027\u0027)) is None]"},{"line_number":345,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"ef8b57ad_302faa48","line":342,"in_reply_to":"8294114c_56aea67c","updated":"2021-11-17 00:18:26.000000000","message":"Done","commit_id":"5a7cf2aaa379f6d43eea468ef36b005020ed979c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"62ca863f9c6cc6c057bca521c0e41af4ecf62d85","unresolved":true,"context_lines":[{"line_number":347,"context_line":"                    new_uploads, prefix, delimiter)"},{"line_number":348,"context_line":"            uploads.extend(new_uploads)"},{"line_number":349,"context_line":"            prefixes.extend(new_prefixes)"},{"line_number":350,"context_line":"            query[\u0027marker\u0027] \u003d objects[-1][\u0027name\u0027]"},{"line_number":351,"context_line":""},{"line_number":352,"context_line":"        truncated \u003d len(uploads) \u003e\u003d maxuploads"},{"line_number":353,"context_line":"        if len(uploads) \u003e maxuploads:"}],"source_content_type":"text/x-python","patch_set":3,"id":"9fb7df68_9c4a5904","line":350,"updated":"2022-01-25 21:04:31.000000000","message":"Pretty sure we want something like\n\n if six.PY2:\n     query[\u0027marker\u0027] \u003d objects[-1][\u0027name\u0027].encode(\u0027utf-8\u0027)\n else:\n     query[\u0027marker\u0027] \u003d objects[-1][\u0027name\u0027]","commit_id":"bdf16423d1c567af55dcd937a0c45db23d5a7e62"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"5d9e0eacb3fc3c1fc74bd1ad3dc680ffd981480e","unresolved":false,"context_lines":[{"line_number":347,"context_line":"                    new_uploads, prefix, delimiter)"},{"line_number":348,"context_line":"            uploads.extend(new_uploads)"},{"line_number":349,"context_line":"            prefixes.extend(new_prefixes)"},{"line_number":350,"context_line":"            query[\u0027marker\u0027] \u003d objects[-1][\u0027name\u0027]"},{"line_number":351,"context_line":""},{"line_number":352,"context_line":"        truncated \u003d len(uploads) \u003e\u003d maxuploads"},{"line_number":353,"context_line":"        if len(uploads) \u003e maxuploads:"}],"source_content_type":"text/x-python","patch_set":3,"id":"d1bc76a5_1e2e4efd","line":350,"in_reply_to":"9fb7df68_9c4a5904","updated":"2022-02-04 07:16:37.000000000","message":"Done","commit_id":"bdf16423d1c567af55dcd937a0c45db23d5a7e62"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"f2ce0e4755c90c1e7ead5c44cb729444422e8765","unresolved":true,"context_lines":[{"line_number":349,"context_line":"            prefixes.extend(new_prefixes)"},{"line_number":350,"context_line":"            query[\u0027marker\u0027] \u003d objects[-1][\u0027name\u0027]"},{"line_number":351,"context_line":""},{"line_number":352,"context_line":"        truncated \u003d len(uploads) \u003e\u003d maxuploads"},{"line_number":353,"context_line":"        if len(uploads) \u003e maxuploads:"},{"line_number":354,"context_line":"            uploads \u003d uploads[:maxuploads]"},{"line_number":355,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"79bc7656_4be544f5","line":352,"updated":"2021-11-18 19:33:50.000000000","message":"When they\u0027re equal, is it really truncated? I suppose the answer may mostly depend on whether objects is an empty list or not...","commit_id":"bdf16423d1c567af55dcd937a0c45db23d5a7e62"},{"author":{"_account_id":17363,"name":"Timur Alperovich","email":"timur@timuralp.com","username":"timuralp"},"change_message_id":"974b26ec51a11fb10633b8a36c9e70f7a70aa65d","unresolved":true,"context_lines":[{"line_number":349,"context_line":"            prefixes.extend(new_prefixes)"},{"line_number":350,"context_line":"            query[\u0027marker\u0027] \u003d objects[-1][\u0027name\u0027]"},{"line_number":351,"context_line":""},{"line_number":352,"context_line":"        truncated \u003d len(uploads) \u003e\u003d maxuploads"},{"line_number":353,"context_line":"        if len(uploads) \u003e maxuploads:"},{"line_number":354,"context_line":"            uploads \u003d uploads[:maxuploads]"},{"line_number":355,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"662d00e3_816dba12","line":352,"in_reply_to":"79bc7656_4be544f5","updated":"2021-11-18 19:44:22.000000000","message":"I think if the number of `uploads` equals `maxuploads`, we can\u0027t tell if it\u0027s truncated so should return \"truncated\" and the client can make one more request.","commit_id":"bdf16423d1c567af55dcd937a0c45db23d5a7e62"}],"test/unit/common/middleware/s3api/test_multi_upload.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c01c75e093ab8f385260cf48deb88e39a7cae497","unresolved":true,"context_lines":[{"line_number":252,"context_line":"            {\u0027name\u0027: name, \u0027last_modified\u0027: \u00272014-05-07T19:47:50.592270\u0027,"},{"line_number":253,"context_line":"             \u0027hash\u0027: \u0027HASH\u0027, \u0027bytes\u0027: 42}"},{"line_number":254,"context_line":"            for upload in uploads for name in upload"},{"line_number":255,"context_line":"        ]"},{"line_number":256,"context_line":"        end \u003d 1000"},{"line_number":257,"context_line":"        while True:"},{"line_number":258,"context_line":"            if end \u003d\u003d 1000:"}],"source_content_type":"text/x-python","patch_set":2,"id":"a322b383_a5ad77e9","line":255,"updated":"2021-10-15 15:40:12.000000000","message":"am I missing where this list gets sorted so the fake swift API responses would match container server API responses?","commit_id":"5a7cf2aaa379f6d43eea468ef36b005020ed979c"},{"author":{"_account_id":17363,"name":"Timur Alperovich","email":"timur@timuralp.com","username":"timuralp"},"change_message_id":"9752ce14eade13855bb0f82094448d781f265382","unresolved":true,"context_lines":[{"line_number":252,"context_line":"            {\u0027name\u0027: name, \u0027last_modified\u0027: \u00272014-05-07T19:47:50.592270\u0027,"},{"line_number":253,"context_line":"             \u0027hash\u0027: \u0027HASH\u0027, \u0027bytes\u0027: 42}"},{"line_number":254,"context_line":"            for upload in uploads for name in upload"},{"line_number":255,"context_line":"        ]"},{"line_number":256,"context_line":"        end \u003d 1000"},{"line_number":257,"context_line":"        while True:"},{"line_number":258,"context_line":"            if end \u003d\u003d 1000:"}],"source_content_type":"text/x-python","patch_set":2,"id":"45cc1552_25f93ade","line":255,"in_reply_to":"a322b383_a5ad77e9","updated":"2021-11-17 00:18:26.000000000","message":"Does the container server API not return them in sorted order? These are sorted when they\u0027re defined on line 245. I may not be following your comment.","commit_id":"5a7cf2aaa379f6d43eea468ef36b005020ed979c"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c01c75e093ab8f385260cf48deb88e39a7cae497","unresolved":true,"context_lines":[{"line_number":266,"context_line":"                    swob.HTTPOk, {}, json.dumps(objects[end - 1000:end]))"},{"line_number":267,"context_line":"            if not objects[end - 1000:end]:"},{"line_number":268,"context_line":"                break"},{"line_number":269,"context_line":"            end +\u003d 1000"},{"line_number":270,"context_line":"        req \u003d Request.blank(\u0027/bucket/?uploads\u0027,"},{"line_number":271,"context_line":"                            environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027GET\u0027},"},{"line_number":272,"context_line":"                            headers\u003d{\u0027Authorization\u0027: \u0027AWS test:tester:hmac\u0027,"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf6c8847_1211b934","line":269,"updated":"2021-10-15 15:40:12.000000000","message":"I wonder if it would be easier to demonsrate the change is obviously correct with a functional test?","commit_id":"5a7cf2aaa379f6d43eea468ef36b005020ed979c"},{"author":{"_account_id":17363,"name":"Timur Alperovich","email":"timur@timuralp.com","username":"timuralp"},"change_message_id":"9752ce14eade13855bb0f82094448d781f265382","unresolved":true,"context_lines":[{"line_number":266,"context_line":"                    swob.HTTPOk, {}, json.dumps(objects[end - 1000:end]))"},{"line_number":267,"context_line":"            if not objects[end - 1000:end]:"},{"line_number":268,"context_line":"                break"},{"line_number":269,"context_line":"            end +\u003d 1000"},{"line_number":270,"context_line":"        req \u003d Request.blank(\u0027/bucket/?uploads\u0027,"},{"line_number":271,"context_line":"                            environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027GET\u0027},"},{"line_number":272,"context_line":"                            headers\u003d{\u0027Authorization\u0027: \u0027AWS test:tester:hmac\u0027,"}],"source_content_type":"text/x-python","patch_set":2,"id":"2f8dce10_7280bc2e","line":269,"in_reply_to":"bf6c8847_1211b934","updated":"2021-11-17 00:18:26.000000000","message":"I\u0027m unsure. Maybe if there is an easy way to twiddle the maximum returned number of entries from the container server to force pagination? Otherwise uploading \u003e 1000 objects would make for a slower test.","commit_id":"5a7cf2aaa379f6d43eea468ef36b005020ed979c"}]}
