)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"a8037138fcfdb8bae7af4d67163d1949f12ef19b","unresolved":false,"context_lines":[{"line_number":7,"context_line":"Have expirer use IC\u0027s delete_object"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"That way, it properly drains the response and we\u0027ll see logs/stats for"},{"line_number":10,"context_line":"404s and 409s."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"Change-Id: I1d5c6e40e1833c53994f8e15b4850871789413ac"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"3ce910ad_ac4b570a","line":10,"updated":"2021-01-11 04:38:50.000000000","message":"Not sure if I\u0027m asking too much, but I wonder if we could have a test to show 404 and/or 409s are now in logs? Just because you\u0027ve gone to the effort of adding it to the commit message?\n\nBut also happy to have my arm twisted to ignore it :P","commit_id":"1db54462206d47885c42cd5c456f0bf07926523e"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"e1b1f212d8334ec72705bf0987b7e84ac31349af","unresolved":false,"context_lines":[{"line_number":7,"context_line":"Have expirer use IC\u0027s delete_object"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"That way, it properly drains the response and we\u0027ll see logs/stats for"},{"line_number":10,"context_line":"404s and 409s."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"Change-Id: I1d5c6e40e1833c53994f8e15b4850871789413ac"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"15bd0d02_5316bfe9","line":10,"in_reply_to":"3ce910ad_ac4b570a","updated":"2021-06-23 23:49:51.000000000","message":"It\u0027s a bit tricky, given how we currently do tests. I mean, the behavior we\u0027re interested in is covered by\n\n test/unit/common/test_internal_client.py:TestInternalClient.test_delete_object\n\nbut since we\u0027re mocking out the whole of InternalClient, it\u0027s not easy to get the test I\u0027d kind of want to see. Maybe I should at least get an assertion against *that* API, though? Hmm... Well, I took out the make_request method for the fake, so at least that\u0027s something.","commit_id":"1db54462206d47885c42cd5c456f0bf07926523e"}],"swift/common/internal_client.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":662,"context_line":"        # in proxy-server"},{"line_number":663,"context_line":"        with closing_if_possible(resp.app_iter):"},{"line_number":664,"context_line":"            for iter_body in resp.app_iter:"},{"line_number":665,"context_line":"                pass"},{"line_number":666,"context_line":""},{"line_number":667,"context_line":"    def get_object_metadata("},{"line_number":668,"context_line":"            self, account, container, obj, metadata_prefix\u003d\u0027\u0027,"}],"source_content_type":"text/x-python","patch_set":4,"id":"0554f55c_e77c603f","side":"PARENT","line":665,"updated":"2021-07-07 18:49:26.000000000","message":"this seems to be about what drain_and_close is doing...","commit_id":"14b1a54af6202ce74ca77fb0e2f15e7b6c23889d"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":221,"context_line":"                        drain_and_close(resp)"},{"line_number":222,"context_line":"                    else:"},{"line_number":223,"context_line":"                        # Just close; the 499 is appropriate"},{"line_number":224,"context_line":"                        close_if_possible(resp.app_iter)"},{"line_number":225,"context_line":"                sleep(2 ** (attempt + 1))"},{"line_number":226,"context_line":"        if resp:"},{"line_number":227,"context_line":"            msg \u003d \u0027Unexpected response: %s\u0027 % resp.status"}],"source_content_type":"text/x-python","patch_set":4,"id":"59a2dc5d_eb239173","line":224,"updated":"2021-07-07 18:49:26.000000000","message":"i think this is all equivalent, but I guess this is only the retry case","commit_id":"45a5ecc8a148a0f1c494d88b5d982cf236be489f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":659,"context_line":"                                 acceptable_statuses)"},{"line_number":660,"context_line":"        # Drain the response body to prevent unexpected disconnect"},{"line_number":661,"context_line":"        # in proxy-server"},{"line_number":662,"context_line":"        drain_and_close(resp)"},{"line_number":663,"context_line":""},{"line_number":664,"context_line":"    def get_object_metadata("},{"line_number":665,"context_line":"            self, account, container, obj, metadata_prefix\u003d\u0027\u0027,"}],"source_content_type":"text/x-python","patch_set":4,"id":"40c53367_e3d95b0b","line":662,"updated":"2021-07-07 18:49:26.000000000","message":"and so using seift.delete_object instead of make_request we always get the drain_and_close(resp) for free","commit_id":"45a5ecc8a148a0f1c494d88b5d982cf236be489f"}],"swift/obj/expirer.py":[{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"3c15a151a7919daae834c2746670e9c36200521d","unresolved":false,"context_lines":[{"line_number":33,"context_line":"    RateLimitedIterator"},{"line_number":34,"context_line":"from swift.common.http import HTTP_NOT_FOUND, HTTP_CONFLICT, \\"},{"line_number":35,"context_line":"    HTTP_PRECONDITION_FAILED"},{"line_number":36,"context_line":"from swift.common.swob import wsgi_quote, str_to_wsgi"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"from swift.container.reconciler import direct_delete_container_entry"},{"line_number":39,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"1f621f24_89d4b6ea","line":36,"updated":"2020-11-13 21:22:21.000000000","message":"pep8: F401 \u0027swift.common.swob.str_to_wsgi\u0027 imported but unused","commit_id":"e8bd9e4fa7c8ac923614c6f61397a2e449b98307"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"3c15a151a7919daae834c2746670e9c36200521d","unresolved":false,"context_lines":[{"line_number":33,"context_line":"    RateLimitedIterator"},{"line_number":34,"context_line":"from swift.common.http import HTTP_NOT_FOUND, HTTP_CONFLICT, \\"},{"line_number":35,"context_line":"    HTTP_PRECONDITION_FAILED"},{"line_number":36,"context_line":"from swift.common.swob import wsgi_quote, str_to_wsgi"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"from swift.container.reconciler import direct_delete_container_entry"},{"line_number":39,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"1f621f24_a9d9b222","line":36,"updated":"2020-11-13 21:22:21.000000000","message":"pep8: F401 \u0027swift.common.swob.wsgi_quote\u0027 imported but unused","commit_id":"e8bd9e4fa7c8ac923614c6f61397a2e449b98307"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"a8037138fcfdb8bae7af4d67163d1949f12ef19b","unresolved":false,"context_lines":[{"line_number":493,"context_line":"                       \u0027X-If-Delete-At\u0027: timestamp.normal,"},{"line_number":494,"context_line":"                       \u0027X-Backend-Clean-Expiring-Object-Queue\u0027: \u0027no\u0027}"},{"line_number":495,"context_line":"            acceptable_statuses \u003d (2, HTTP_CONFLICT)"},{"line_number":496,"context_line":"        self.swift.delete_object(*split_path(\u0027/\u0027 + actual_obj, 3, 3, True),"},{"line_number":497,"context_line":"                                 headers\u003dheaders,"},{"line_number":498,"context_line":"                                 acceptable_statuses\u003dacceptable_statuses)"}],"source_content_type":"text/x-python","patch_set":2,"id":"b6bb4f0b_2754bacc","line":496,"updated":"2021-01-11 04:38:50.000000000","message":"Sigh, this wsgistr stuff will forever be the bane of our existance.. thanks for continuing to remind us how it works Tim :P","commit_id":"1db54462206d47885c42cd5c456f0bf07926523e"},{"author":{"_account_id":597,"name":"Pete Zaitcev","email":"zaitcev@kotori.zaitcev.us","username":"zaitcev"},"change_message_id":"bc77c9230c23f928aff45014ad74fa41e41f7355","unresolved":false,"context_lines":[{"line_number":493,"context_line":"                       \u0027X-If-Delete-At\u0027: timestamp.normal,"},{"line_number":494,"context_line":"                       \u0027X-Backend-Clean-Expiring-Object-Queue\u0027: \u0027no\u0027}"},{"line_number":495,"context_line":"            acceptable_statuses \u003d (2, HTTP_CONFLICT)"},{"line_number":496,"context_line":"        self.swift.delete_object(*split_path(\u0027/\u0027 + actual_obj, 3, 3, True),"},{"line_number":497,"context_line":"                                 headers\u003dheaders,"},{"line_number":498,"context_line":"                                 acceptable_statuses\u003dacceptable_statuses)"}],"source_content_type":"text/x-python","patch_set":2,"id":"1f621f24_bf7e00e1","line":496,"updated":"2020-11-14 07:16:39.000000000","message":"Wait a moment, delete_object just does make_path and then make_request. Surely it wants a wsgi a, c, o. Right? But the expirer appears to manipulate with straight-up unicode when composing task lists. Maybe I\u0027m just confused.","commit_id":"1db54462206d47885c42cd5c456f0bf07926523e"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"f20adf4f5c6c98cb2acc103bfff6dc3446e25ee2","unresolved":false,"context_lines":[{"line_number":493,"context_line":"                       \u0027X-If-Delete-At\u0027: timestamp.normal,"},{"line_number":494,"context_line":"                       \u0027X-Backend-Clean-Expiring-Object-Queue\u0027: \u0027no\u0027}"},{"line_number":495,"context_line":"            acceptable_statuses \u003d (2, HTTP_CONFLICT)"},{"line_number":496,"context_line":"        self.swift.delete_object(*split_path(\u0027/\u0027 + actual_obj, 3, 3, True),"},{"line_number":497,"context_line":"                                 headers\u003dheaders,"},{"line_number":498,"context_line":"                                 acceptable_statuses\u003dacceptable_statuses)"}],"source_content_type":"text/x-python","patch_set":2,"id":"1f621f24_0f3362ac","line":496,"in_reply_to":"1f621f24_bf7e00e1","updated":"2020-11-17 19:37:37.000000000","message":"The wsgi dance I introduced in https://review.opendev.org/#/c/659189/ was probably unnecessary; internal_client\u0027s interface deals in native strings (and, on py2, unicode strings -- I should probably make it behave better with bytes on py3...)\n\nSo, we hand native strings to delete_object, make_path ensures it\u0027s all quoted (using a utf8 encoding) as we pass it to swob.Request.blank, which then unquotes it using latin1 to get us back to WSGI. Blech.","commit_id":"1db54462206d47885c42cd5c456f0bf07926523e"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":487,"context_line":"        :raises UnexpectedResponse: if the delete was unsuccessful and"},{"line_number":488,"context_line":"                                    should be retried later"},{"line_number":489,"context_line":"        \"\"\""},{"line_number":490,"context_line":"        path \u003d \u0027/v1/\u0027 + wsgi_quote(str_to_wsgi(actual_obj.lstrip(\u0027/\u0027)))"},{"line_number":491,"context_line":"        if is_async_delete:"},{"line_number":492,"context_line":"            headers \u003d {\u0027X-Timestamp\u0027: timestamp.normal}"},{"line_number":493,"context_line":"            acceptable_statuses \u003d (2, HTTP_CONFLICT, HTTP_NOT_FOUND)"}],"source_content_type":"text/x-python","patch_set":4,"id":"53735f4e_7c1b7f7c","side":"PARENT","line":490,"updated":"2021-07-07 18:49:26.000000000","message":"so i guess the `\u0027/\u0027 + actual_object(\u0027/\u0027)` was mostly being defensive to the tests?","commit_id":"14b1a54af6202ce74ca77fb0e2f15e7b6c23889d"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":496,"context_line":"                       \u0027X-If-Delete-At\u0027: timestamp.normal,"},{"line_number":497,"context_line":"                       \u0027X-Backend-Clean-Expiring-Object-Queue\u0027: \u0027no\u0027}"},{"line_number":498,"context_line":"            acceptable_statuses \u003d (2, HTTP_CONFLICT)"},{"line_number":499,"context_line":"        self.swift.make_request(\u0027DELETE\u0027, path, headers, acceptable_statuses)"}],"source_content_type":"text/x-python","patch_set":4,"id":"8f40a51c_56d66ce1","side":"PARENT","line":499,"updated":"2021-07-07 18:49:26.000000000","message":"so the \"bug\" as it were was NOT calling drain_and_close on the resp returned here","commit_id":"14b1a54af6202ce74ca77fb0e2f15e7b6c23889d"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":290,"context_line":"                       \u0027task_container\u0027: task_container,"},{"line_number":291,"context_line":"                       \u0027task_object\u0027: task_object,"},{"line_number":292,"context_line":"                       \u0027target_path\u0027: \u0027/\u0027.join(["},{"line_number":293,"context_line":"                           target_account, target_container, target_object]),"},{"line_number":294,"context_line":"                       \u0027delete_timestamp\u0027: delete_timestamp,"},{"line_number":295,"context_line":"                       \u0027is_async_delete\u0027: is_async}"},{"line_number":296,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"4f4b2a41_0125e844","line":293,"updated":"2021-07-07 18:49:26.000000000","message":"the target_path does not include the leading `/`","commit_id":"45a5ecc8a148a0f1c494d88b5d982cf236be489f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":357,"context_line":"                    delete_task_iter,"},{"line_number":358,"context_line":"                    elements_per_second\u003dself.tasks_per_second)"},{"line_number":359,"context_line":"                for delete_task in rate_limited_iter:"},{"line_number":360,"context_line":"                    pool.spawn_n(self.delete_object, **delete_task)"},{"line_number":361,"context_line":""},{"line_number":362,"context_line":"            pool.waitall()"},{"line_number":363,"context_line":"            for task_account, task_container in \\"}],"source_content_type":"text/x-python","patch_set":4,"id":"5ea646f0_25cf0a77","line":360,"updated":"2021-07-07 18:49:26.000000000","message":"delete_object gets the whole task dict","commit_id":"45a5ecc8a148a0f1c494d88b5d982cf236be489f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":431,"context_line":"        start_time \u003d time()"},{"line_number":432,"context_line":"        try:"},{"line_number":433,"context_line":"            try:"},{"line_number":434,"context_line":"                self.delete_actual_object(target_path, delete_timestamp,"},{"line_number":435,"context_line":"                                          is_async_delete)"},{"line_number":436,"context_line":"            except UnexpectedResponse as err:"},{"line_number":437,"context_line":"                if err.resp.status_int not in {HTTP_NOT_FOUND,"}],"source_content_type":"text/x-python","patch_set":4,"id":"9ae231cd_1cc3f522","line":434,"updated":"2021-07-07 18:49:26.000000000","message":"and target_path is passed through unmolested to delete_actual_object","commit_id":"45a5ecc8a148a0f1c494d88b5d982cf236be489f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":476,"context_line":"        of the object is exactly the timestamp given."},{"line_number":477,"context_line":""},{"line_number":478,"context_line":"        :param actual_obj: The name of the end-user object to delete:"},{"line_number":479,"context_line":"                           \u0027\u003caccount\u003e/\u003ccontainer\u003e/\u003cobject\u003e\u0027"},{"line_number":480,"context_line":"        :param timestamp: The swift.common.utils.Timestamp instance the"},{"line_number":481,"context_line":"                          X-Delete-At value must match to perform the actual"},{"line_number":482,"context_line":"                          delete."}],"source_content_type":"text/x-python","patch_set":4,"id":"63c9aeff_67e9bcfd","line":479,"updated":"2021-07-07 18:49:26.000000000","message":"maybe it\u0027d be more clear if the signature carried forward the \"target_path\" name from the \"delete_task\"","commit_id":"45a5ecc8a148a0f1c494d88b5d982cf236be489f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":494,"context_line":"                       \u0027X-If-Delete-At\u0027: timestamp.normal,"},{"line_number":495,"context_line":"                       \u0027X-Backend-Clean-Expiring-Object-Queue\u0027: \u0027no\u0027}"},{"line_number":496,"context_line":"            acceptable_statuses \u003d (2, HTTP_CONFLICT)"},{"line_number":497,"context_line":"        self.swift.delete_object(*split_path(\u0027/\u0027 + actual_obj, 3, 3, True),"},{"line_number":498,"context_line":"                                 headers\u003dheaders,"},{"line_number":499,"context_line":"                                 acceptable_statuses\u003dacceptable_statuses)"}],"source_content_type":"text/x-python","patch_set":4,"id":"47916c6a_f519259c","line":497,"updated":"2021-07-07 18:49:26.000000000","message":"it\u0027s a little hard to see because this is so dense, but the signature is delete_object(a, c, o, **kwargs) - and under the hood it\u0027s using make_path to add the `/v1` for the IC request.","commit_id":"45a5ecc8a148a0f1c494d88b5d982cf236be489f"}],"test/unit/obj/test_expirer.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":138,"context_line":"                    self.future_time + \u0027-a11/c11/o11\u0027]}"},{"line_number":139,"context_line":"        })"},{"line_number":140,"context_line":"        self.expirer \u003d expirer.ObjectExpirer(self.conf, logger\u003dself.logger,"},{"line_number":141,"context_line":"                                             swift\u003dself.fake_swift)"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"        # target object paths which should be expirerd now"},{"line_number":144,"context_line":"        self.expired_target_path_list \u003d ["}],"source_content_type":"text/x-python","patch_set":4,"id":"6819c8c4_70aa613a","line":141,"updated":"2021-07-07 18:49:26.000000000","message":"some of these tests aren\u0027t using internal client","commit_id":"45a5ecc8a148a0f1c494d88b5d982cf236be489f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":936,"context_line":"            def fake_app(env, start_response):"},{"line_number":937,"context_line":"                calls[0] +\u003d 1"},{"line_number":938,"context_line":"                start_response(test_status, [(\u0027Content-Length\u0027, \u00270\u0027)])"},{"line_number":939,"context_line":"                return []"},{"line_number":940,"context_line":""},{"line_number":941,"context_line":"            internal_client.loadapp \u003d lambda *a, **kw: fake_app"},{"line_number":942,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"33042886_0ed2ad53","line":939,"updated":"2021-07-07 18:49:26.000000000","message":"but some tests just mock out the proxy_app at the end of internal_client pipeline\n\nwe could probably model a test after this to verify this app_iter is drained and closed in the 4XX/2XX cases","commit_id":"45a5ecc8a148a0f1c494d88b5d982cf236be489f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5878affd7932f18064ac264f5d83427c0e7ddf14","unresolved":true,"context_lines":[{"line_number":979,"context_line":"        self.assertEqual(503, exc.resp.status_int)"},{"line_number":980,"context_line":""},{"line_number":981,"context_line":"    def test_delete_actual_object_quotes(self):"},{"line_number":982,"context_line":"        name \u003d \u0027this name/should get/quoted\u0027"},{"line_number":983,"context_line":"        timestamp \u003d Timestamp(\u00271366063156.863045\u0027)"},{"line_number":984,"context_line":"        x \u003d expirer.ObjectExpirer({})"},{"line_number":985,"context_line":"        x.swift.make_request \u003d mock.Mock()"}],"source_content_type":"text/x-python","patch_set":4,"id":"6d1661cc_57bdf7e5","line":982,"updated":"2021-07-07 18:49:26.000000000","message":"the split_path parsing now requires the path to split to a/c/o","commit_id":"45a5ecc8a148a0f1c494d88b5d982cf236be489f"}]}
