)]}'
{"swift/obj/diskfile.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"3ef81706050a47931dbaf1f52e864c44f68dd221","unresolved":false,"context_lines":[{"line_number":542,"context_line":"        for ext in (\u0027.data\u0027, \u0027.meta\u0027, \u0027.ts\u0027):"},{"line_number":543,"context_line":"            filename \u003d accepted_files.get(ext)"},{"line_number":544,"context_line":"            key \u003d \u0027%s_file\u0027 % ext[1:]"},{"line_number":545,"context_line":"            result[key] \u003d join(datadir, filename) if filename else None"},{"line_number":546,"context_line":"        if (\u0027.data\u0027 in accepted_files and \u0027fragments\u0027 in accepted_files"},{"line_number":547,"context_line":"                and len(accepted_files[\u0027fragments\u0027]) \u003e 1):"},{"line_number":548,"context_line":"            # if there are alternate frags to report, add them to the list"}],"source_content_type":"text/x-python","patch_set":4,"id":"fa1b9901_0f1572e3","line":545,"updated":"2015-08-20 18:47:09.000000000","message":"I\u0027m +2 for this change to return a dict but wonder if we can\u0027t push it further - return all the result from accepted_files then let ECDiskFile implement the following lines (which are EC specific).\n\nI did just that in my dependent patch https://review.openstack.org/215276","commit_id":"09db8b34f02ed7656f60c62245d0b8e189f3d0fa"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":538,"context_line":"                  \u0027meta_file\u0027 and optionally \u0027alt_frags\u0027"},{"line_number":539,"context_line":"        \"\"\""},{"line_number":540,"context_line":"        accepted_files \u003d self.gather_ondisk_files(files, verify\u003dTrue, **kwargs)"},{"line_number":541,"context_line":"        result \u003d {}"},{"line_number":542,"context_line":"        for ext in (\u0027.data\u0027, \u0027.meta\u0027, \u0027.ts\u0027):"},{"line_number":543,"context_line":"            filename \u003d accepted_files.get(ext)"},{"line_number":544,"context_line":"            key \u003d \u0027%s_file\u0027 % ext[1:]"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_b62bb3ea","line":541,"updated":"2015-09-11 17:02:49.000000000","message":"we could just add the fully qualified file paths to the existing accepted_files dict and return it - exposing all the ondisk search info to the DiskFile class wil be great for future enhancements (like returning non-durables)...","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":543,"context_line":"            filename \u003d accepted_files.get(ext)"},{"line_number":544,"context_line":"            key \u003d \u0027%s_file\u0027 % ext[1:]"},{"line_number":545,"context_line":"            result[key] \u003d join(datadir, filename) if filename else None"},{"line_number":546,"context_line":"        if (\u0027.data\u0027 in accepted_files and \u0027fragments\u0027 in accepted_files"},{"line_number":547,"context_line":"                and len(accepted_files[\u0027fragments\u0027]) \u003e 1):"},{"line_number":548,"context_line":"            # if there are alternate frags to report, add them to the list"},{"line_number":549,"context_line":"            # minus the FI for the returned data file of course"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_f645abb3","line":546,"updated":"2015-09-11 17:02:49.000000000","message":"... and then this can be moved to ECDiskFile since it is EC specific behavior.","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"}],"swift/proxy/controllers/base.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":1203,"context_line":"                self.app.logger.increment(\u0027handoff_all_count\u0027)"},{"line_number":1204,"context_line":""},{"line_number":1205,"context_line":"    def add_nodes(self, nodes):"},{"line_number":1206,"context_line":"        self.alt_nodes \u003d nodes"},{"line_number":1207,"context_line":"        self.nodes_left \u003d len(nodes)"},{"line_number":1208,"context_line":""},{"line_number":1209,"context_line":"    def _alt_gen(self):"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_940d4791","line":1206,"updated":"2015-09-11 17:02:49.000000000","message":"should this be :\n\n  self.alt_nodes +\u003d nodes","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":1206,"context_line":"        self.alt_nodes \u003d nodes"},{"line_number":1207,"context_line":"        self.nodes_left \u003d len(nodes)"},{"line_number":1208,"context_line":""},{"line_number":1209,"context_line":"    def _alt_gen(self):"},{"line_number":1210,"context_line":"        for node in self.alt_nodes:"},{"line_number":1211,"context_line":"            if not self.app.error_limited(node):"},{"line_number":1212,"context_line":"                yield node"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_af4d9273","line":1209,"updated":"2015-09-11 17:02:49.000000000","message":"I think there is a problem with using a generator like this - once alt_nodes has been exhausted and a StopIteration raised, then generator will not yield anything again - even if new alt nodes are appended to self.alt_nodes.","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":1235,"context_line":"                        return"},{"line_number":1236,"context_line":""},{"line_number":1237,"context_line":"    def next(self):"},{"line_number":1238,"context_line":"        if len(self.alt_nodes) \u003e 0:"},{"line_number":1239,"context_line":"            return next(self._alt_iter)"},{"line_number":1240,"context_line":"        else:"},{"line_number":1241,"context_line":"            return next(self._node_iter)"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_54b83375","line":1238,"updated":"2015-09-11 17:02:49.000000000","message":"nothing is decrementing the length of alt_nodes so once this condition is True how does it become False again?","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":1237,"context_line":"    def next(self):"},{"line_number":1238,"context_line":"        if len(self.alt_nodes) \u003e 0:"},{"line_number":1239,"context_line":"            return next(self._alt_iter)"},{"line_number":1240,"context_line":"        else:"},{"line_number":1241,"context_line":"            return next(self._node_iter)"},{"line_number":1242,"context_line":""},{"line_number":1243,"context_line":"    def __next__(self):"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_4fdb967c","line":1240,"updated":"2015-09-11 17:02:49.000000000","message":"do we want to get smart and insert alt_nodes ahead of handoffs but behind primaries - by maybe splitting node_iter into two iters - one for primaries and one handoffs?","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"}],"swift/proxy/controllers/obj.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":1967,"context_line":"                        # check for alternates"},{"line_number":1968,"context_line":"                        alternates \u003d HeaderKeyDict("},{"line_number":1969,"context_line":"                            get.last_headers)[\u0027X-Backend-Alt-Frag-Index\u0027]"},{"line_number":1970,"context_line":"                        if alternates and len(alt_nodes) \u003d\u003d 0:"},{"line_number":1971,"context_line":"                                alternates \u003d alternates.strip(\u0027[]\u0027)"},{"line_number":1972,"context_line":"                                if len(alternates) \u003e 0:"},{"line_number":1973,"context_line":"                                    for index in alternates:"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_742537ac","line":1970,"updated":"2015-09-11 17:02:49.000000000","message":"why \u0027and len(alt_nodes) \u003d\u003d 0\u0027 ? - that means we don\u0027t collect alternates from other nodes once we have some from one node.","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":1968,"context_line":"                        alternates \u003d HeaderKeyDict("},{"line_number":1969,"context_line":"                            get.last_headers)[\u0027X-Backend-Alt-Frag-Index\u0027]"},{"line_number":1970,"context_line":"                        if alternates and len(alt_nodes) \u003d\u003d 0:"},{"line_number":1971,"context_line":"                                alternates \u003d alternates.strip(\u0027[]\u0027)"},{"line_number":1972,"context_line":"                                if len(alternates) \u003e 0:"},{"line_number":1973,"context_line":"                                    for index in alternates:"},{"line_number":1974,"context_line":"                                        alt_node \u003d get.node.copy()"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_341fbf5c","line":1971,"updated":"2015-09-11 17:02:49.000000000","message":"strip [] not necessary but we do need to split(\u0027,\u0027)","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":1970,"context_line":"                        if alternates and len(alt_nodes) \u003d\u003d 0:"},{"line_number":1971,"context_line":"                                alternates \u003d alternates.strip(\u0027[]\u0027)"},{"line_number":1972,"context_line":"                                if len(alternates) \u003e 0:"},{"line_number":1973,"context_line":"                                    for index in alternates:"},{"line_number":1974,"context_line":"                                        alt_node \u003d get.node.copy()"},{"line_number":1975,"context_line":"                                        alt_node[\u0027frag_index\u0027] \u003d index"},{"line_number":1976,"context_line":"                                        alt_nodes.append(alt_node)"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_744c5776","line":1973,"updated":"2015-09-11 17:02:49.000000000","message":"1. needs a split else this will iterate over e.g. index\u003d \u00271\u0027  index\u003d \u0027,\u0027  index\u003d \u00272\u0027\n\n2. need to remove frags that we have already found to avoid also adding them to alts when fetching the alt.\n\ne.g. good get for frag 1 has alt 2; later we go get frag 2 and get alt\u003d1.","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":1994,"context_line":"                        # nodes in node_iter we can spawn another"},{"line_number":1995,"context_line":"                        pile.spawn(self._fragment_GET_request, req,"},{"line_number":1996,"context_line":"                                   safe_iter, partition, policy)"},{"line_number":1997,"context_line":"                    elif len(alt_nodes) \u003e 0:"},{"line_number":1998,"context_line":"                        # we didn\u0027t have enough but alternates were reported"},{"line_number":1999,"context_line":"                        # so fire up a new node_iter to fetch the alternates"},{"line_number":2000,"context_line":"                        node_iter.add_nodes(alt_nodes)"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_942ecb40","line":1997,"updated":"2015-09-11 17:02:49.000000000","message":"the elif doesn\u0027t seem right, but I haven\u0027t yet constructed what it should be :)\n\nWhen the if condition is not met we are either on target to get enough frags (happy path) or we\u0027ve exhausted the node iter. The latter case seems to be when we\u0027d want to inject the alt_nodes. \n\nOr... maybe we inject the alt nodes when the first part of the condition is met i.e. we need to spawn some more getters, so let them have a go at the alt nodes.\n\nIn fact - perhaps we should just inject the alt nodes into the iterator as soon as we find them and then make the node iterator yield them at the appropriate time i.e. before or after primaries.","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"},{"author":{"_account_id":7479,"name":"paul luse","email":"paul.e.luse@intel.com","username":"peluse"},"change_message_id":"b2cf7a580f2d18e354adf333124c62cda331a83b","unresolved":false,"context_lines":[{"line_number":1996,"context_line":"                                   safe_iter, partition, policy)"},{"line_number":1997,"context_line":"                    elif len(alt_nodes) \u003e 0:"},{"line_number":1998,"context_line":"                        # we didn\u0027t have enough but alternates were reported"},{"line_number":1999,"context_line":"                        # so fire up a new node_iter to fetch the alternates"},{"line_number":2000,"context_line":"                        node_iter.add_nodes(alt_nodes)"},{"line_number":2001,"context_line":"                        alt_nodes \u003d []"},{"line_number":2002,"context_line":"                        pile.spawn(self._fragment_GET_request, req,"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_baa149f9","line":1999,"updated":"2015-09-04 15:11:51.000000000","message":"outdated comment... will change the thing about firing up a new node_iter since that\u0027s clearly not what we\u0027re doing here","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":1999,"context_line":"                        # so fire up a new node_iter to fetch the alternates"},{"line_number":2000,"context_line":"                        node_iter.add_nodes(alt_nodes)"},{"line_number":2001,"context_line":"                        alt_nodes \u003d []"},{"line_number":2002,"context_line":"                        pile.spawn(self._fragment_GET_request, req,"},{"line_number":2003,"context_line":"                                   safe_iter, partition, policy)"},{"line_number":2004,"context_line":""},{"line_number":2005,"context_line":"            req.range \u003d orig_range"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_afa112ab","line":2002,"updated":"2015-09-11 17:02:49.000000000","message":"If we have no pending getters and then add \u003e1 alt_nodes, we need to spawn one getter per alt_node.\n\nBut I think its better to move injecting alt_nodes earlier and rely on the existing re-spawning to add getters as needed.","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"}],"test/unit/obj/test_server.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":1705,"context_line":"            # now phony up some alt FA\u0027s to bre reported back for EC"},{"line_number":1706,"context_line":"            # policies only"},{"line_number":1707,"context_line":"            if policy.policy_type \u003d\u003d EC_POLICY:"},{"line_number":1708,"context_line":"                # now lets drop 2 dummy FI (0, 1) in there as well"},{"line_number":1709,"context_line":"                obj_dir \u003d os.path.join("},{"line_number":1710,"context_line":"                    self.testdir, \u0027sda1\u0027,"},{"line_number":1711,"context_line":"                    storage_directory(diskfile.get_data_dir(int(policy)),"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_2f0d023e","line":1708,"updated":"2015-09-11 17:02:49.000000000","message":"could use PUTs with X-Backend-Ssync-Frag-Index to make alt frags \"for real\"","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":1734,"context_line":"            else:"},{"line_number":1735,"context_line":"                self.assertTrue(\u0027X-Backend-Alt-Frag-Index\u0027 not in"},{"line_number":1736,"context_line":"                                resp.headers)"},{"line_number":1737,"context_line":"            self.assertEqual(resp.body, \u0027VERIFY\u0027)"},{"line_number":1738,"context_line":""},{"line_number":1739,"context_line":"            # now prefer something that misses"},{"line_number":1740,"context_line":"            headers \u003d {\u0027X-Backend-Storage-Policy-Index\u0027: int(policy),"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_cfcc8637","line":1737,"updated":"2015-09-11 17:02:49.000000000","message":"I tried to extend this test to get back the other frags too, but discovered that copy2 does not copy xattrs, so the phoney diskfile is invalid.\n\nUsing another PUT to create the alt frags gets around that problem.","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"}],"test/unit/proxy/test_server.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1692084ff56554cfaaa636e20ac5b514e26878ad","unresolved":false,"context_lines":[{"line_number":6039,"context_line":"        # node 2: FA 1 and FA 2"},{"line_number":6040,"context_line":"        # node 3: FA3"},{"line_number":6041,"context_line":"        # node 4: FA4"},{"line_number":6042,"context_line":"        # node 5: \u003cnothing\u003e"},{"line_number":6043,"context_line":"        # a GET will see 404 on 3 nodes which is not enough to decode so will"},{"line_number":6044,"context_line":"        # examine resp headers from node 2 and see that it has an alternate"},{"line_number":6045,"context_line":"        # so before rejecting the GET it will execute a GET for the alt FA on"}],"source_content_type":"text/x-python","patch_set":5,"id":"da20952f_0a2eec8b","line":6042,"updated":"2015-09-11 17:02:49.000000000","message":"I tried 2 nodes with an alt frag on each and 4 nodes with nothing and got a 404 :(","commit_id":"03bfbf5349b7dc2dce5b50f95da7c27abbbb2942"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e89c856134f614462837bb687ab5d0a28c8b5305","unresolved":false,"context_lines":[{"line_number":6155,"context_line":"                fa \u003d [f for f in os.listdir(src_dir) if \"#\" in f][0]"},{"line_number":6156,"context_line":"                src \u003d os.path.join(src_dir, fa)"},{"line_number":6157,"context_line":"                dest \u003d os.path.join(node_hash_dirs[dest_node], fa)"},{"line_number":6158,"context_line":"                copy(src, dest)"},{"line_number":6159,"context_line":""},{"line_number":6160,"context_line":"            # GET the obj again, potentially now using alternate frags"},{"line_number":6161,"context_line":"            get_req \u003d Request.blank(\"/v1/a/fec-con/obj\","}],"source_content_type":"text/x-python","patch_set":8,"id":"ba15a1d1_40d32260","line":6158,"updated":"2015-09-18 07:52:14.000000000","message":"I think I noticed on some other test I was working on that copy() does not copy the xattrs :( So the copied .data file is not a valid diskfile because it has no metadata when opened. That may (or may not) explain why the test fails.\n\nDouble-check what I am saying but if its true then it would be great to have a helper method somewhere in the test framework that does copy_with_xattrs.","commit_id":"b89393196e7156d971f11223b9726d62008105b1"}]}
