| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 from file_system import FileSystem, StatInfo, FileNotFoundError | 5 from file_system import FileSystem, StatInfo, FileNotFoundError |
| 6 from future import Future | 6 from future import Future |
| 7 | 7 |
| 8 class _AsyncUncachedFuture(object): | 8 class _AsyncUncachedFuture(object): |
| 9 def __init__(self, | 9 def __init__(self, |
| 10 uncached, | 10 uncached, |
| 11 current_result, | 11 current_result, |
| 12 file_system, | 12 file_system, |
| 13 object_store): | 13 object_store): |
| 14 self._uncached = uncached | 14 self._uncached = uncached |
| 15 self._current_result = current_result | 15 self._current_result = current_result |
| 16 self._file_system = file_system | 16 self._file_system = file_system |
| 17 self._object_store = object_store | 17 self._object_store = object_store |
| 18 | 18 |
| 19 def Get(self): | 19 def Get(self): |
| 20 mapping = {} | 20 mapping = {} |
| 21 new_items = self._uncached.Get() | 21 new_items = self._uncached.Get() |
| 22 for item in new_items: | 22 for item in new_items: |
| 23 version = self._file_system.Stat(item).version | 23 version = self._file_system.Stat(item).version |
| 24 mapping[item] = (new_items[item], version) | 24 mapping[item] = (new_items[item], version) |
| 25 self._current_result[item] = new_items[item] | 25 self._current_result[item] = new_items[item] |
| 26 self._object_store.SetMulti(mapping, time=0) | 26 self._object_store.SetMulti(mapping) |
| 27 return self._current_result | 27 return self._current_result |
| 28 | 28 |
| 29 class CachingFileSystem(FileSystem): | 29 class CachingFileSystem(FileSystem): |
| 30 """FileSystem implementation which caches its results in an object store. | 30 """FileSystem implementation which caches its results in an object store. |
| 31 """ | 31 """ |
| 32 def __init__(self, file_system, object_store_creator_factory): | 32 def __init__(self, file_system, object_store_creator_factory): |
| 33 self._file_system = file_system | 33 self._file_system = file_system |
| 34 def create_object_store(category): | 34 def create_object_store(category): |
| 35 return (object_store_creator_factory.Create(CachingFileSystem) | 35 return (object_store_creator_factory.Create(CachingFileSystem) |
| 36 .Create(category=category, version=file_system.GetVersion())) | 36 .Create(category='%s/%s' % (file_system.GetName(), category), |
| 37 version=file_system.GetVersion())) |
| 37 self._stat_object_store = create_object_store('stat') | 38 self._stat_object_store = create_object_store('stat') |
| 38 self._read_object_store = create_object_store('read') | 39 self._read_object_store = create_object_store('read') |
| 39 self._read_binary_object_store = create_object_store('read-binary') | 40 self._read_binary_object_store = create_object_store('read-binary') |
| 40 | 41 |
| 41 def Stat(self, path, stats=None): | 42 def Stat(self, path, stats=None): |
| 42 """Stats the directory given, or if a file is given, stats the files parent | 43 """Stats the directory given, or if a file is given, stats the files parent |
| 43 directory to get info about the file. | 44 directory to get info about the file. |
| 44 """ | 45 """ |
| 45 # TODO(kalman): store the whole stat info, not just the version. | 46 # TODO(kalman): store the whole stat info, not just the version. |
| 46 version = self._stat_object_store.Get(path).Get() | 47 version = self._stat_object_store.Get(path).Get() |
| (...skipping 19 matching lines...) Expand all Loading... |
| 66 for child_path, child_version in dir_stat.child_versions.iteritems(): | 67 for child_path, child_version in dir_stat.child_versions.iteritems(): |
| 67 child_path = dir_path + child_path | 68 child_path = dir_path + child_path |
| 68 mapping[child_path] = child_version | 69 mapping[child_path] = child_version |
| 69 self._stat_object_store.SetMulti(mapping) | 70 self._stat_object_store.SetMulti(mapping) |
| 70 return StatInfo(version) | 71 return StatInfo(version) |
| 71 | 72 |
| 72 def Read(self, paths, binary=False): | 73 def Read(self, paths, binary=False): |
| 73 """Reads a list of files. If a file is in memcache and it is not out of | 74 """Reads a list of files. If a file is in memcache and it is not out of |
| 74 date, it is returned. Otherwise, the file is retrieved from the file system. | 75 date, it is returned. Otherwise, the file is retrieved from the file system. |
| 75 """ | 76 """ |
| 77 read_object_store = (self._read_binary_object_store if binary else |
| 78 self._read_object_store) |
| 79 read_values = read_object_store.GetMulti(paths).Get() |
| 80 stat_values = self._stat_object_store.GetMulti(paths).Get() |
| 76 result = {} | 81 result = {} |
| 77 uncached = [] | 82 uncached = [] |
| 78 read_object_store = (self._read_binary_object_store if binary else | 83 for path in paths: |
| 79 self._read_object_store) | 84 read_value = read_values.get(path) |
| 80 results = read_object_store.GetMulti(paths).Get() | 85 stat_value = stat_values.get(path) |
| 81 result_values = [x[1] for x in sorted(results.iteritems())] | 86 if read_value is None: |
| 82 stats = self._stat_object_store.GetMulti(paths).Get() | |
| 83 stat_values = [x[1] for x in sorted(stats.iteritems())] | |
| 84 for path, cached_result, stat in zip(sorted(paths), | |
| 85 result_values, | |
| 86 stat_values): | |
| 87 if cached_result is None: | |
| 88 uncached.append(path) | 87 uncached.append(path) |
| 89 continue | 88 continue |
| 90 data, version = cached_result | 89 data, version = read_value |
| 91 # TODO(cduvall): Make this use a multi stat. | 90 # TODO(cduvall): Make this use a multi stat. |
| 92 if stat is None: | 91 if stat_value is None: |
| 93 stat = self.Stat(path).version | 92 stat_value = self.Stat(path).version |
| 94 if stat != version: | 93 if stat_value != version: |
| 95 uncached.append(path) | 94 uncached.append(path) |
| 96 continue | 95 continue |
| 97 result[path] = data | 96 result[path] = data |
| 98 | 97 |
| 99 if not uncached: | 98 if not uncached: |
| 100 return Future(value=result) | 99 return Future(value=result) |
| 100 |
| 101 return Future(delegate=_AsyncUncachedFuture( | 101 return Future(delegate=_AsyncUncachedFuture( |
| 102 self._file_system.Read(uncached, binary=binary), | 102 self._file_system.Read(uncached, binary=binary), |
| 103 result, | 103 result, |
| 104 self, | 104 self, |
| 105 read_object_store)) | 105 read_object_store)) |
| OLD | NEW |