)]}'
{"glance/common/utils.py":[{"author":{"_account_id":6549,"name":"Zhi Yan Liu","email":"lzy.dev@gmail.com","username":"lzy-dev"},"change_message_id":"fc84d6f61ac2777bec156905c67ff81995409017","unresolved":false,"context_lines":[{"line_number":88,"context_line":"            yield chunk"},{"line_number":89,"context_line":"        else:"},{"line_number":90,"context_line":"            break"},{"line_number":91,"context_line":""},{"line_number":92,"context_line":"def cooperative_iter(iter, cache_file\u003dNone, checksum\u003dNone):"},{"line_number":93,"context_line":"    \"\"\""},{"line_number":94,"context_line":"    Return an iterator which schedules after each"}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FKDg%3D","line":91,"updated":"2013-11-13 16:23:54.000000000","message":"Pep8 require 2 blank lines here.","commit_id":"0253fd9af0924f33f738c646917636c8e592b96c"},{"author":{"_account_id":6737,"name":"Edward Hope-Morley","email":"edward.hope-morley@canonical.com","username":"hopem"},"change_message_id":"238499d06d9fe679ec7161ff94b04451d31968ee","unresolved":false,"context_lines":[{"line_number":88,"context_line":"            yield chunk"},{"line_number":89,"context_line":"        else:"},{"line_number":90,"context_line":"            break"},{"line_number":91,"context_line":""},{"line_number":92,"context_line":"def cooperative_iter(iter, cache_file\u003dNone, checksum\u003dNone):"},{"line_number":93,"context_line":"    \"\"\""},{"line_number":94,"context_line":"    Return an iterator which schedules after each"}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FJ9k%3D","line":91,"in_reply_to":"AAAATn%2F%2FKDg%3D","updated":"2013-11-13 16:36:20.000000000","message":"Done","commit_id":"0253fd9af0924f33f738c646917636c8e592b96c"},{"author":{"_account_id":6549,"name":"Zhi Yan Liu","email":"lzy.dev@gmail.com","username":"lzy-dev"},"change_message_id":"fc84d6f61ac2777bec156905c67ff81995409017","unresolved":false,"context_lines":[{"line_number":89,"context_line":"        else:"},{"line_number":90,"context_line":"            break"},{"line_number":91,"context_line":""},{"line_number":92,"context_line":"def cooperative_iter(iter, cache_file\u003dNone, checksum\u003dNone):"},{"line_number":93,"context_line":"    \"\"\""},{"line_number":94,"context_line":"    Return an iterator which schedules after each"},{"line_number":95,"context_line":"    iteration. This can prevent eventlet thread starvation."}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FKAc%3D","line":92,"updated":"2013-11-13 16:23:54.000000000","message":"I know this is a simple and direct approach, but TBH I don\u0027t think it\u0027s a good choice to put upper layer logic into this common function directly, says put cache_file and checksum here. they are not related with cooperative_iter(). IMHO, we can add a call back hook function param at here, and implements cache logic in that helper, and pass it in at upper cache code.","commit_id":"0253fd9af0924f33f738c646917636c8e592b96c"},{"author":{"_account_id":455,"name":"Stuart McLaren","email":"stuart.mclaren@hpe.com","username":"stuart-mclaren"},"change_message_id":"aa8c7e4b746a71b474c642fcae07b3f2c149988f","unresolved":false,"context_lines":[{"line_number":89,"context_line":"        else:"},{"line_number":90,"context_line":"            break"},{"line_number":91,"context_line":""},{"line_number":92,"context_line":"def cooperative_iter(iter, cache_file\u003dNone, checksum\u003dNone):"},{"line_number":93,"context_line":"    \"\"\""},{"line_number":94,"context_line":"    Return an iterator which schedules after each"},{"line_number":95,"context_line":"    iteration. This can prevent eventlet thread starvation."}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FJ%2BA%3D","line":92,"in_reply_to":"AAAATn%2F%2FKAc%3D","updated":"2013-11-13 16:32:52.000000000","message":"I tend to agree with Zhi here. Its nicer to have a simple cooperative_iter utility that doesn\u0027t need to know anything about the cache etc.","commit_id":"0253fd9af0924f33f738c646917636c8e592b96c"},{"author":{"_account_id":6737,"name":"Edward Hope-Morley","email":"edward.hope-morley@canonical.com","username":"hopem"},"change_message_id":"238499d06d9fe679ec7161ff94b04451d31968ee","unresolved":false,"context_lines":[{"line_number":89,"context_line":"        else:"},{"line_number":90,"context_line":"            break"},{"line_number":91,"context_line":""},{"line_number":92,"context_line":"def cooperative_iter(iter, cache_file\u003dNone, checksum\u003dNone):"},{"line_number":93,"context_line":"    \"\"\""},{"line_number":94,"context_line":"    Return an iterator which schedules after each"},{"line_number":95,"context_line":"    iteration. This can prevent eventlet thread starvation."}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FJ8c%3D","line":92,"in_reply_to":"AAAATn%2F%2FKAc%3D","updated":"2013-11-13 16:36:20.000000000","message":"i kinda fell like adding callback hooks for before and after the yield is gonna be nasty and make things harder to debug when things go wrong. If this is such a concern then I can move this back to the image cache layer but then the whole point of doing this was to make it more general.","commit_id":"0253fd9af0924f33f738c646917636c8e592b96c"},{"author":{"_account_id":455,"name":"Stuart McLaren","email":"stuart.mclaren@hpe.com","username":"stuart-mclaren"},"change_message_id":"2b4663d8fe3b5de51a0450d55323aef1b1389043","unresolved":false,"context_lines":[{"line_number":157,"context_line":"            return \u0027\u0027"},{"line_number":158,"context_line":""},{"line_number":159,"context_line":"    def __iter__(self):"},{"line_number":160,"context_line":"        return cooperative_iter(self.fd)"},{"line_number":161,"context_line":""},{"line_number":162,"context_line":""},{"line_number":163,"context_line":"class LimitingReader(object):"}],"source_content_type":"text/x-python","patch_set":5,"id":"AAAATn%2F%2BMiI%3D","line":160,"updated":"2013-11-29 11:06:18.000000000","message":"What\u0027s the purpose of this change? Thanks.","commit_id":"19c5ee467cdd49fd02af878d2869d3b7cbc854f0"},{"author":{"_account_id":6737,"name":"Edward Hope-Morley","email":"edward.hope-morley@canonical.com","username":"hopem"},"change_message_id":"6a45efdf6d84f9d37dd3b465e00450b2f65c5397","unresolved":false,"context_lines":[{"line_number":157,"context_line":"            return \u0027\u0027"},{"line_number":158,"context_line":""},{"line_number":159,"context_line":"    def __iter__(self):"},{"line_number":160,"context_line":"        return cooperative_iter(self.fd)"},{"line_number":161,"context_line":""},{"line_number":162,"context_line":""},{"line_number":163,"context_line":"class LimitingReader(object):"}],"source_content_type":"text/x-python","patch_set":5,"id":"AAAATn%2F%2BMN0%3D","line":160,"in_reply_to":"AAAATn%2F%2BMiI%3D","updated":"2013-11-29 12:48:11.000000000","message":"Apologies, this was required by the previous patchset and should have been removed.","commit_id":"19c5ee467cdd49fd02af878d2869d3b7cbc854f0"}],"glance/image_cache/__init__.py":[{"author":{"_account_id":6549,"name":"Zhi Yan Liu","email":"lzy.dev@gmail.com","username":"lzy-dev"},"change_message_id":"fc84d6f61ac2777bec156905c67ff81995409017","unresolved":false,"context_lines":[{"line_number":19,"context_line":"LRU Cache for Image Data"},{"line_number":20,"context_line":"\"\"\""},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"import eventlet"},{"line_number":23,"context_line":"import hashlib"},{"line_number":24,"context_line":"from oslo.config import cfg"},{"line_number":25,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FKFI%3D","line":22,"updated":"2013-11-13 16:23:54.000000000","message":"Useless","commit_id":"0253fd9af0924f33f738c646917636c8e592b96c"},{"author":{"_account_id":6737,"name":"Edward Hope-Morley","email":"edward.hope-morley@canonical.com","username":"hopem"},"change_message_id":"238499d06d9fe679ec7161ff94b04451d31968ee","unresolved":false,"context_lines":[{"line_number":19,"context_line":"LRU Cache for Image Data"},{"line_number":20,"context_line":"\"\"\""},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"import eventlet"},{"line_number":23,"context_line":"import hashlib"},{"line_number":24,"context_line":"from oslo.config import cfg"},{"line_number":25,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FJ9o%3D","line":22,"in_reply_to":"AAAATn%2F%2FKFI%3D","updated":"2013-11-13 16:36:20.000000000","message":"oops forgot to remove this.","commit_id":"0253fd9af0924f33f738c646917636c8e592b96c"},{"author":{"_account_id":455,"name":"Stuart McLaren","email":"stuart.mclaren@hpe.com","username":"stuart-mclaren"},"change_message_id":"6d821742e063ebd98061297bd3331cbb2cec4a1a","unresolved":false,"context_lines":[{"line_number":240,"context_line":"        try:"},{"line_number":241,"context_line":"            current_checksum \u003d hashlib.md5()"},{"line_number":242,"context_line":"            with self.driver.open_for_write(image_id) as cache_file:"},{"line_number":243,"context_line":"                for chunk in utils.CooperativeReader(image_iter, cache_file,"},{"line_number":244,"context_line":"                                                     current_checksum):"},{"line_number":245,"context_line":"                    yield chunk"},{"line_number":246,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FJ44%3D","line":243,"updated":"2013-11-13 16:50:49.000000000","message":"In v1 we do this at the download layer which makes downloads co-operative whether or not the cache is configured. It also means that this code change will be wrapping one co-operative iter in another for v1 downloads. Is it possible to do this in the v2 download layer instead?","commit_id":"0253fd9af0924f33f738c646917636c8e592b96c"},{"author":{"_account_id":7884,"name":"Noboru Arai","email":"arai@mxa.nes.nec.co.jp","username":"NoboruArai"},"change_message_id":"2f91550fd38e7c00e3f515ec30edc81bd2f82ae5","unresolved":false,"context_lines":[{"line_number":19,"context_line":"LRU Cache for Image Data"},{"line_number":20,"context_line":"\"\"\""},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"import eventlet"},{"line_number":23,"context_line":"import hashlib"},{"line_number":24,"context_line":"from oslo.config import cfg"},{"line_number":25,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"AAAATn%2F%2FIWs%3D","line":22,"updated":"2013-11-14 02:54:16.000000000","message":"Is this import statement necessary?\n\nI seem that your modification is adding call of \"utils.CooperativeReader\" .\nBut  there is \"utils.CooperativeReader\"  method in glance/common/utils.py.","commit_id":"bb4b1281ed82ae8eeb1f65685441d1ff238ceb44"},{"author":{"_account_id":6737,"name":"Edward Hope-Morley","email":"edward.hope-morley@canonical.com","username":"hopem"},"change_message_id":"d92a59619c51257db007d0257eedfbea4dbf6c0d","unresolved":false,"context_lines":[{"line_number":19,"context_line":"LRU Cache for Image Data"},{"line_number":20,"context_line":"\"\"\""},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"import eventlet"},{"line_number":23,"context_line":"import hashlib"},{"line_number":24,"context_line":"from oslo.config import cfg"},{"line_number":25,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"AAAATn%2F%2FF%2BQ%3D","line":22,"in_reply_to":"AAAATn%2F%2FIWs%3D","updated":"2013-11-14 14:01:01.000000000","message":"Yes your are right I forgot to remove it. Actually this patch may now be abandoned but i have yet to verify.","commit_id":"bb4b1281ed82ae8eeb1f65685441d1ff238ceb44"},{"author":{"_account_id":455,"name":"Stuart McLaren","email":"stuart.mclaren@hpe.com","username":"stuart-mclaren"},"change_message_id":"2b4663d8fe3b5de51a0450d55323aef1b1389043","unresolved":false,"context_lines":[{"line_number":242,"context_line":"            current_checksum \u003d hashlib.md5()"},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"            with self.driver.open_for_write(image_id) as cache_file:"},{"line_number":245,"context_line":"                for chunk in utils.CooperativeReader(image_iter):"},{"line_number":246,"context_line":"                    try:"},{"line_number":247,"context_line":"                        cache_file.write(chunk)"},{"line_number":248,"context_line":"                    finally:"}],"source_content_type":"text/x-python","patch_set":5,"id":"AAAATn%2F%2BMhg%3D","line":245,"updated":"2013-11-29 11:06:18.000000000","message":"For v1 I think image_iter is already wrapped in a cooperative_reader at this point (glance/api/v1/images.py). We should try to avoid wrapping a second time I think.","commit_id":"19c5ee467cdd49fd02af878d2869d3b7cbc854f0"},{"author":{"_account_id":6737,"name":"Edward Hope-Morley","email":"edward.hope-morley@canonical.com","username":"hopem"},"change_message_id":"02a1d1242c2dfa0e8ef23416e44a89ebd7f25d1f","unresolved":false,"context_lines":[{"line_number":242,"context_line":"            current_checksum \u003d hashlib.md5()"},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"            with self.driver.open_for_write(image_id) as cache_file:"},{"line_number":245,"context_line":"                for chunk in utils.CooperativeReader(image_iter):"},{"line_number":246,"context_line":"                    try:"},{"line_number":247,"context_line":"                        cache_file.write(chunk)"},{"line_number":248,"context_line":"                    finally:"}],"source_content_type":"text/x-python","patch_set":5,"id":"AAAATn%2F%2BMJM%3D","line":245,"in_reply_to":"AAAATn%2F%2BMKg%3D","updated":"2013-11-29 13:11:47.000000000","message":"Of course cause that\u0027s the iterator used for the tee (but not the cache read). Good call. Still writing response to main message...","commit_id":"19c5ee467cdd49fd02af878d2869d3b7cbc854f0"},{"author":{"_account_id":455,"name":"Stuart McLaren","email":"stuart.mclaren@hpe.com","username":"stuart-mclaren"},"change_message_id":"a7ad020044e3b84cd49f21a4c9d209e4d2da3f30","unresolved":false,"context_lines":[{"line_number":242,"context_line":"            current_checksum \u003d hashlib.md5()"},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"            with self.driver.open_for_write(image_id) as cache_file:"},{"line_number":245,"context_line":"                for chunk in utils.CooperativeReader(image_iter):"},{"line_number":246,"context_line":"                    try:"},{"line_number":247,"context_line":"                        cache_file.write(chunk)"},{"line_number":248,"context_line":"                    finally:"}],"source_content_type":"text/x-python","patch_set":5,"id":"AAAATn%2F%2BMKg%3D","line":245,"in_reply_to":"AAAATn%2F%2BMNI%3D","updated":"2013-11-29 12:57:40.000000000","message":"I\u0027m thinking of the v1 download code:\n\nglance/api/v1/images.py:\n\n    def show(self, req, id):\n        \"\"\"\n        Returns an iterator that can be used to retrieve an image\u0027s\n        data along with the image metadata.\n\n        :param req: The WSGI/Webob Request object\n        :param id: The opaque image identifier\n\n        :raises HTTPNotFound if image is not available to user\n        \"\"\"\n        self._enforce(req, \u0027get_image\u0027)\n        self._enforce(req, \u0027download_image\u0027)\n        image_meta \u003d self.get_active_image_meta_or_404(req, id)\n\n        self._enforce_read_protected_props(image_meta, req)\n\n        if image_meta.get(\u0027size\u0027) \u003d\u003d 0:\n            image_iterator \u003d iter([])\n        else:\n            image_iterator, size \u003d self._get_from_store(req.context,\n                                                        image_meta[\u0027location\u0027])\n            image_iterator \u003d utils.cooperative_iter(image_iterator) \u003c\u003c\u003c\n            image_meta[\u0027size\u0027] \u003d size or image_meta[\u0027size\u0027]\n\n        del image_meta[\u0027location\u0027]\n        return {\n            \u0027image_iterator\u0027: image_iterator,\n            \u0027image_meta\u0027: image_meta,\n        }\n\nputting a print statement in the cooperative_iter would help verify.","commit_id":"19c5ee467cdd49fd02af878d2869d3b7cbc854f0"},{"author":{"_account_id":6737,"name":"Edward Hope-Morley","email":"edward.hope-morley@canonical.com","username":"hopem"},"change_message_id":"6a45efdf6d84f9d37dd3b465e00450b2f65c5397","unresolved":false,"context_lines":[{"line_number":242,"context_line":"            current_checksum \u003d hashlib.md5()"},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"            with self.driver.open_for_write(image_id) as cache_file:"},{"line_number":245,"context_line":"                for chunk in utils.CooperativeReader(image_iter):"},{"line_number":246,"context_line":"                    try:"},{"line_number":247,"context_line":"                        cache_file.write(chunk)"},{"line_number":248,"context_line":"                    finally:"}],"source_content_type":"text/x-python","patch_set":5,"id":"AAAATn%2F%2BMNI%3D","line":245,"in_reply_to":"AAAATn%2F%2BMhg%3D","updated":"2013-11-29 12:48:11.000000000","message":"Stuart, I\u0027m gonna reply to your main comment but just briefly, I could not find evidence that this is cooperative so if you can point out something to the contrary that would be great. Having said that, I am not convinced that this should be cooperative but I\u0027ll continue this in my main reply.","commit_id":"19c5ee467cdd49fd02af878d2869d3b7cbc854f0"}]}
