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 |