)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"6fd2dddc164d38079830f63b8afc4a0d38eef354","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"4f9362bb_fc98dabe","updated":"2024-11-12 23:26:29.000000000","message":"``-1`` because zuul is not happy, complains from pep8.","commit_id":"91b4e877c6005173b3a2376d35af1bbc7dbf4067"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3d685051ef7ea28cb8cd8f3fcda345b347497505","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"6cf5402f_5f49434f","updated":"2024-11-13 15:45:43.000000000","message":"some of these comments might be stale - i forgot to click submit after the last round/patchset.","commit_id":"a8922ac52a96123fb8e8144e3aef6cf16620aa16"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"fffedc47f087e500e4c0743b3a3b3d08fde0b00e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"415d9c3b_d2587c4e","updated":"2024-11-13 22:48:21.000000000","message":"I have a different view on why slow deletion happens, but I am willing to test this patch on production to verify the author\u0027s assumption of GIL and see if this patch makes a difference.","commit_id":"66eff91d3b7fbd32826a7414f793dacbe9ea1da8"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"399a4586fa5f2a15e268b23226b4e8cadf3fc84d","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":6,"id":"83a8895d_5fee622f","updated":"2024-12-04 17:33:23.000000000","message":"We can mark this patch as active since i was able to resolve merge conflicts on this one","commit_id":"b5abf3aeb5cf5ffc1f7184032d23d17c767a3d98"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"608b1b1bfda6f0a1f24f763caab4c591938ea76c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"22eaa483_68054fa8","in_reply_to":"83a8895d_5fee622f","updated":"2024-12-04 17:33:45.000000000","message":"Done","commit_id":"b5abf3aeb5cf5ffc1f7184032d23d17c767a3d98"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"65fdf924f272f893f9e821fd0ad8a714d71aa652","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"3c431df1_10c8ee05","updated":"2024-12-09 17:11:06.000000000","message":"recheck\n\nI think this code is not robust to eventual consistency:\n\nhttps://github.com/openstack/tempest/blob/master/tempest/common/object_storage.py\n\nI might should look for a bug report","commit_id":"ddbc202e3adcf4feaa28d51a63b455e1aff6895b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ab1fa93f3587490a7654708633820713f8982d4b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"845f0553_737152f3","updated":"2025-01-16 12:21:01.000000000","message":"recheck","commit_id":"33694599a30c0d51e6c657446b1ab24cdfc1c0cd"}],"swift/obj/diskfile.py":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"6fd2dddc164d38079830f63b8afc4a0d38eef354","unresolved":true,"context_lines":[{"line_number":1375,"context_line":"            if recursion_depth \u003e\u003d 5:"},{"line_number":1376,"context_line":"                # \u003e\u003e\u003e sum([2 ** i * 0.1 for i in range(5)])"},{"line_number":1377,"context_line":"                # 3.1"},{"line_number":1378,"context_line":"                raise SuffixSyncError(\u0027Too many attempts to get_hashes\u0027)"},{"line_number":1379,"context_line":"            sleep(2 ** recursion_depth * 0.1)"},{"line_number":1380,"context_line":"            return self.__get_hashes(device, partition, policy,"},{"line_number":1381,"context_line":"                                     recalculate\u003drecalculate,"}],"source_content_type":"text/x-python","patch_set":1,"id":"a48c835d_2bca94f9","line":1378,"updated":"2024-11-12 23:26:29.000000000","message":"this means the hierarchy of directories within a partition won\u0027t go beyond 5? also some comments will be great.","commit_id":"91b4e877c6005173b3a2376d35af1bbc7dbf4067"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"fffedc47f087e500e4c0743b3a3b3d08fde0b00e","unresolved":false,"context_lines":[{"line_number":1375,"context_line":"            if recursion_depth \u003e\u003d 5:"},{"line_number":1376,"context_line":"                # \u003e\u003e\u003e sum([2 ** i * 0.1 for i in range(5)])"},{"line_number":1377,"context_line":"                # 3.1"},{"line_number":1378,"context_line":"                raise SuffixSyncError(\u0027Too many attempts to get_hashes\u0027)"},{"line_number":1379,"context_line":"            sleep(2 ** recursion_depth * 0.1)"},{"line_number":1380,"context_line":"            return self.__get_hashes(device, partition, policy,"},{"line_number":1381,"context_line":"                                     recalculate\u003drecalculate,"}],"source_content_type":"text/x-python","patch_set":1,"id":"03c79bdf_ec95134d","line":1378,"in_reply_to":"2c548c2d_bd03e95f","updated":"2024-11-13 22:48:21.000000000","message":"Acknowledged","commit_id":"91b4e877c6005173b3a2376d35af1bbc7dbf4067"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"5d5c4335210b277244018c41eafb5f7cdfda1767","unresolved":false,"context_lines":[{"line_number":1375,"context_line":"            if recursion_depth \u003e\u003d 5:"},{"line_number":1376,"context_line":"                # \u003e\u003e\u003e sum([2 ** i * 0.1 for i in range(5)])"},{"line_number":1377,"context_line":"                # 3.1"},{"line_number":1378,"context_line":"                raise SuffixSyncError(\u0027Too many attempts to get_hashes\u0027)"},{"line_number":1379,"context_line":"            sleep(2 ** recursion_depth * 0.1)"},{"line_number":1380,"context_line":"            return self.__get_hashes(device, partition, policy,"},{"line_number":1381,"context_line":"                                     recalculate\u003drecalculate,"}],"source_content_type":"text/x-python","patch_set":1,"id":"7467c48f_8e609a80","line":1378,"in_reply_to":"a48c835d_2bca94f9","updated":"2024-11-13 05:59:59.000000000","message":"oic. this is used to avoid ``__get_hashes`` from being called too many times to handle transient synchronization issues. Makes sense to me to set a limit of retries.","commit_id":"91b4e877c6005173b3a2376d35af1bbc7dbf4067"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3d685051ef7ea28cb8cd8f3fcda345b347497505","unresolved":true,"context_lines":[{"line_number":1375,"context_line":"            if recursion_depth \u003e\u003d 5:"},{"line_number":1376,"context_line":"                # \u003e\u003e\u003e sum([2 ** i * 0.1 for i in range(5)])"},{"line_number":1377,"context_line":"                # 3.1"},{"line_number":1378,"context_line":"                raise SuffixSyncError(\u0027Too many attempts to get_hashes\u0027)"},{"line_number":1379,"context_line":"            sleep(2 ** recursion_depth * 0.1)"},{"line_number":1380,"context_line":"            return self.__get_hashes(device, partition, policy,"},{"line_number":1381,"context_line":"                                     recalculate\u003drecalculate,"}],"source_content_type":"text/x-python","patch_set":1,"id":"2c548c2d_bd03e95f","line":1378,"in_reply_to":"a48c835d_2bca94f9","updated":"2024-11-13 15:45:43.000000000","message":"the directory depth is not related.  recursion here signifies a retry because the initial hash state has changed while we were doing the recalc.","commit_id":"91b4e877c6005173b3a2376d35af1bbc7dbf4067"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"6fd2dddc164d38079830f63b8afc4a0d38eef354","unresolved":true,"context_lines":[{"line_number":1376,"context_line":"                # \u003e\u003e\u003e sum([2 ** i * 0.1 for i in range(5)])"},{"line_number":1377,"context_line":"                # 3.1"},{"line_number":1378,"context_line":"                raise SuffixSyncError(\u0027Too many attempts to get_hashes\u0027)"},{"line_number":1379,"context_line":"            sleep(2 ** recursion_depth * 0.1)"},{"line_number":1380,"context_line":"            return self.__get_hashes(device, partition, policy,"},{"line_number":1381,"context_line":"                                     recalculate\u003drecalculate,"},{"line_number":1382,"context_line":"                                     do_listdir\u003ddo_listdir,"}],"source_content_type":"text/x-python","patch_set":1,"id":"7925bc0e_9db61dc4","line":1379,"updated":"2024-11-12 23:26:29.000000000","message":"I don\u0027t understand how threadpool impact green thread, maybe this will give chances for green threads to run. IIUC, if a thread is stuck at listing dir, other threads or greenthread should get CPU?\n\ncan you add more comments here?","commit_id":"91b4e877c6005173b3a2376d35af1bbc7dbf4067"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"5d5c4335210b277244018c41eafb5f7cdfda1767","unresolved":false,"context_lines":[{"line_number":1376,"context_line":"                # \u003e\u003e\u003e sum([2 ** i * 0.1 for i in range(5)])"},{"line_number":1377,"context_line":"                # 3.1"},{"line_number":1378,"context_line":"                raise SuffixSyncError(\u0027Too many attempts to get_hashes\u0027)"},{"line_number":1379,"context_line":"            sleep(2 ** recursion_depth * 0.1)"},{"line_number":1380,"context_line":"            return self.__get_hashes(device, partition, policy,"},{"line_number":1381,"context_line":"                                     recalculate\u003drecalculate,"},{"line_number":1382,"context_line":"                                     do_listdir\u003ddo_listdir,"}],"source_content_type":"text/x-python","patch_set":1,"id":"2a8f5a4b_f62b94a8","line":1379,"in_reply_to":"7925bc0e_9db61dc4","updated":"2024-11-13 05:59:59.000000000","message":"okay, this is an exponential sleep during retries.","commit_id":"91b4e877c6005173b3a2376d35af1bbc7dbf4067"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3d685051ef7ea28cb8cd8f3fcda345b347497505","unresolved":true,"context_lines":[{"line_number":1376,"context_line":"                # \u003e\u003e\u003e sum([2 ** i * 0.1 for i in range(5)])"},{"line_number":1377,"context_line":"                # 3.1"},{"line_number":1378,"context_line":"                raise SuffixSyncError(\u0027Too many attempts to get_hashes\u0027)"},{"line_number":1379,"context_line":"            sleep(2 ** recursion_depth * 0.1)"},{"line_number":1380,"context_line":"            return self.__get_hashes(device, partition, policy,"},{"line_number":1381,"context_line":"                                     recalculate\u003drecalculate,"},{"line_number":1382,"context_line":"                                     do_listdir\u003ddo_listdir,"}],"source_content_type":"text/x-python","patch_set":1,"id":"7dcc869d_fbd052ed","line":1379,"in_reply_to":"7925bc0e_9db61dc4","updated":"2024-11-13 15:45:43.000000000","message":"threadpool allows blocking calls to yield to the eventlet hub; but I think still only when they can release the GIL (i.e. a syscall like readdir/listdir)\n\nMy theory is that somehow this threadpool\u0027d function tends to mostly release the GIL while holding the partition lock - which prevents other greenthreads waiting on the partition lock to add to the invalid file.\n\nThis sleep should also release the GIL back to the main-thread to run greenthreads while not holding the partition lock.\n\nPerhaps interesting it may not be strictly necessary to have the hashes.pkl read and hashes.invalid write use the same lock","commit_id":"91b4e877c6005173b3a2376d35af1bbc7dbf4067"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"fffedc47f087e500e4c0743b3a3b3d08fde0b00e","unresolved":true,"context_lines":[{"line_number":1376,"context_line":"                # \u003e\u003e\u003e sum([2 ** i * 0.1 for i in range(5)])"},{"line_number":1377,"context_line":"                # 3.1"},{"line_number":1378,"context_line":"                raise SuffixSyncError(\u0027Too many attempts to get_hashes\u0027)"},{"line_number":1379,"context_line":"            sleep(2 ** recursion_depth * 0.1)"},{"line_number":1380,"context_line":"            return self.__get_hashes(device, partition, policy,"},{"line_number":1381,"context_line":"                                     recalculate\u003drecalculate,"},{"line_number":1382,"context_line":"                                     do_listdir\u003ddo_listdir,"}],"source_content_type":"text/x-python","patch_set":1,"id":"3a4f0629_c9878d87","line":1379,"in_reply_to":"7dcc869d_fbd052ed","updated":"2024-11-13 22:48:21.000000000","message":"this partition lock is implemented through ``fcntl.flock`` and it uses ``fcntl.LOCK_NB`` to not to block on waiting to get the lock. since this is all memory and no disk I/O involved, should be very quick. The more I look into it, I feel GIL should be release after ``fcntl.flock`` returns.\n```\ndef _get_any_lock(fds):\n    for fd in fds:\n        try:\n            fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)\n            return True\n        except IOError as err:\n            if err.errno !\u003d errno.EAGAIN:\n                raise\n    return False\n```\n\nmaybe it\u0027s just a few of slow disks, and ``read_hashes/write_hashes`` takes a long time to finish, and then the long held partition lock itself will block deletion operations.\n\n```\n        if modified:\n            with lock_path(partition_path):\n                if read_hashes(partition_path) \u003d\u003d orig_hashes:\n                    write_hashes(partition_path, hashes)\n                    return hashed, hashes\n            return self.__get_hashes(device, partition, policy,\n                                     recalculate\u003drecalculate,\n                                     do_listdir\u003ddo_listdir)\n        else:\n            return hashed, hashes\n```\n\nAnd I think it\u0027s necessary to have both hashes.pkl read and hashes.invalid write use the same lock, what if ``lock_path`` and ``read_hashes`` will release GIL and other green thread get scheduled before ``write_hashes`` and then updated the hashes.pkl.\n\nProbably we have to verify all those on production, I am okay to test this patch.","commit_id":"91b4e877c6005173b3a2376d35af1bbc7dbf4067"}],"test/unit/obj/test_diskfile.py":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"5d5c4335210b277244018c41eafb5f7cdfda1767","unresolved":true,"context_lines":[{"line_number":9534,"context_line":"                 \u0027003\u0027: \u0027fake\u0027, \u0027004\u0027: \u0027fake\u0027},  # not modifed"},{"line_number":9535,"context_line":"            ])"},{"line_number":9536,"context_line":""},{"line_number":9537,"context_line":"    def test_get_hashes_modified_recursive_depth(self):"},{"line_number":9538,"context_line":"        policy \u003d POLICIES.default"},{"line_number":9539,"context_line":"        df_mgr \u003d self.df_router[policy]"},{"line_number":9540,"context_line":"        part_path \u003d os.path.join(self.devices, self.existing_device,"}],"source_content_type":"text/x-python","patch_set":2,"id":"f2da1160_a678550b","line":9537,"updated":"2024-11-13 05:59:59.000000000","message":"add another test case which only does retries within the limit (like 2 retries) and verify the new ``hashes.pkl`` file will be written?","commit_id":"a8922ac52a96123fb8e8144e3aef6cf16620aa16"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"fffedc47f087e500e4c0743b3a3b3d08fde0b00e","unresolved":false,"context_lines":[{"line_number":9534,"context_line":"                 \u0027003\u0027: \u0027fake\u0027, \u0027004\u0027: \u0027fake\u0027},  # not modifed"},{"line_number":9535,"context_line":"            ])"},{"line_number":9536,"context_line":""},{"line_number":9537,"context_line":"    def test_get_hashes_modified_recursive_depth(self):"},{"line_number":9538,"context_line":"        policy \u003d POLICIES.default"},{"line_number":9539,"context_line":"        df_mgr \u003d self.df_router[policy]"},{"line_number":9540,"context_line":"        part_path \u003d os.path.join(self.devices, self.existing_device,"}],"source_content_type":"text/x-python","patch_set":2,"id":"569081a4_db4a02ae","line":9537,"in_reply_to":"c229adde_930712d8","updated":"2024-11-13 22:48:21.000000000","message":"Done","commit_id":"a8922ac52a96123fb8e8144e3aef6cf16620aa16"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3d685051ef7ea28cb8cd8f3fcda345b347497505","unresolved":true,"context_lines":[{"line_number":9534,"context_line":"                 \u0027003\u0027: \u0027fake\u0027, \u0027004\u0027: \u0027fake\u0027},  # not modifed"},{"line_number":9535,"context_line":"            ])"},{"line_number":9536,"context_line":""},{"line_number":9537,"context_line":"    def test_get_hashes_modified_recursive_depth(self):"},{"line_number":9538,"context_line":"        policy \u003d POLICIES.default"},{"line_number":9539,"context_line":"        df_mgr \u003d self.df_router[policy]"},{"line_number":9540,"context_line":"        part_path \u003d os.path.join(self.devices, self.existing_device,"}],"source_content_type":"text/x-python","patch_set":2,"id":"c229adde_930712d8","line":9537,"in_reply_to":"f2da1160_a678550b","updated":"2024-11-13 15:45:43.000000000","message":"I think the test case above covers a retry success","commit_id":"a8922ac52a96123fb8e8144e3aef6cf16620aa16"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"5d5c4335210b277244018c41eafb5f7cdfda1767","unresolved":true,"context_lines":[{"line_number":9559,"context_line":"            return rv"},{"line_number":9560,"context_line":"        with mock.patch(\u0027swift.obj.diskfile.read_hashes\u0027, mock_read_hashes), \\"},{"line_number":9561,"context_line":"                mock.patch(\u0027swift.obj.diskfile.sleep\u0027) as mock_sleep, \\"},{"line_number":9562,"context_line":"                self.assertRaises(SuffixSyncError):"},{"line_number":9563,"context_line":"            df_mgr.get_hashes(self.existing_device, \u00270\u0027, [\u0027123\u0027], policy)"},{"line_number":9564,"context_line":"        # 2 calls per 1 + 5 retries?"},{"line_number":9565,"context_line":"        self.assertEqual(12, len(calls), calls)"}],"source_content_type":"text/x-python","patch_set":2,"id":"03327f50_4be9d8a2","line":9562,"updated":"2024-11-13 05:59:59.000000000","message":"nit: also check the message \u0027Too many attempts to get_hashes\u0027","commit_id":"a8922ac52a96123fb8e8144e3aef6cf16620aa16"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3d685051ef7ea28cb8cd8f3fcda345b347497505","unresolved":false,"context_lines":[{"line_number":9559,"context_line":"            return rv"},{"line_number":9560,"context_line":"        with mock.patch(\u0027swift.obj.diskfile.read_hashes\u0027, mock_read_hashes), \\"},{"line_number":9561,"context_line":"                mock.patch(\u0027swift.obj.diskfile.sleep\u0027) as mock_sleep, \\"},{"line_number":9562,"context_line":"                self.assertRaises(SuffixSyncError):"},{"line_number":9563,"context_line":"            df_mgr.get_hashes(self.existing_device, \u00270\u0027, [\u0027123\u0027], policy)"},{"line_number":9564,"context_line":"        # 2 calls per 1 + 5 retries?"},{"line_number":9565,"context_line":"        self.assertEqual(12, len(calls), calls)"}],"source_content_type":"text/x-python","patch_set":2,"id":"643a10de_4239b0f4","line":9562,"in_reply_to":"03327f50_4be9d8a2","updated":"2024-11-13 15:45:43.000000000","message":"Done","commit_id":"a8922ac52a96123fb8e8144e3aef6cf16620aa16"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"5d5c4335210b277244018c41eafb5f7cdfda1767","unresolved":false,"context_lines":[{"line_number":9563,"context_line":"            df_mgr.get_hashes(self.existing_device, \u00270\u0027, [\u0027123\u0027], policy)"},{"line_number":9564,"context_line":"        # 2 calls per 1 + 5 retries?"},{"line_number":9565,"context_line":"        self.assertEqual(12, len(calls), calls)"},{"line_number":9566,"context_line":"        self.assertEqual([mock.call(s) for s in [0.1, 0.2, 0.4, 0.8, 1.6]],"},{"line_number":9567,"context_line":"                         mock_sleep.call_args_list)"},{"line_number":9568,"context_line":""},{"line_number":9569,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"0f3b53ef_feb0fdee","line":9566,"updated":"2024-11-13 05:59:59.000000000","message":"okay, this verifies that the exponential backoff logic is working as expected","commit_id":"a8922ac52a96123fb8e8144e3aef6cf16620aa16"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"5d5c4335210b277244018c41eafb5f7cdfda1767","unresolved":true,"context_lines":[{"line_number":9565,"context_line":"        self.assertEqual(12, len(calls), calls)"},{"line_number":9566,"context_line":"        self.assertEqual([mock.call(s) for s in [0.1, 0.2, 0.4, 0.8, 1.6]],"},{"line_number":9567,"context_line":"                         mock_sleep.call_args_list)"},{"line_number":9568,"context_line":""},{"line_number":9569,"context_line":""},{"line_number":9570,"context_line":"class TestHashesHelpers(unittest.TestCase):"},{"line_number":9571,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"5c4efb54_481c77de","line":9568,"updated":"2024-11-13 05:59:59.000000000","message":"probably also to check the ``hashes.pkl`` file didn\u0027t get written or modified in the partition directory after the 5 retries.","commit_id":"a8922ac52a96123fb8e8144e3aef6cf16620aa16"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3d685051ef7ea28cb8cd8f3fcda345b347497505","unresolved":false,"context_lines":[{"line_number":9565,"context_line":"        self.assertEqual(12, len(calls), calls)"},{"line_number":9566,"context_line":"        self.assertEqual([mock.call(s) for s in [0.1, 0.2, 0.4, 0.8, 1.6]],"},{"line_number":9567,"context_line":"                         mock_sleep.call_args_list)"},{"line_number":9568,"context_line":""},{"line_number":9569,"context_line":""},{"line_number":9570,"context_line":"class TestHashesHelpers(unittest.TestCase):"},{"line_number":9571,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"9436f666_969fb0a6","line":9568,"in_reply_to":"5c4efb54_481c77de","updated":"2024-11-13 15:45:43.000000000","message":"Done","commit_id":"a8922ac52a96123fb8e8144e3aef6cf16620aa16"}]}
