Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(877)

Side by Side Diff: chrome/common/extensions/docs/server2/caching_file_system.py

Issue 512453002: Docserver: Add more skip_not_found support and cache "not found"s (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Bumpin yaml Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 import posixpath 5 import posixpath
6 import sys 6 import sys
7 7
8 from file_system import FileSystem, StatInfo, FileNotFoundError 8 from file_system import FileSystem, StatInfo, FileNotFoundError
9 from future import Future 9 from future import Future
10 from path_util import IsDirectory, ToDirectory 10 from path_util import IsDirectory, ToDirectory
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 return dir_stat 50 return dir_stat
51 # Was a file stat. Extract that file. 51 # Was a file stat. Extract that file.
52 file_version = dir_stat.child_versions.get(file_path) 52 file_version = dir_stat.child_versions.get(file_path)
53 if file_version is None: 53 if file_version is None:
54 raise FileNotFoundError('No stat found for %s in %s (found %s)' % 54 raise FileNotFoundError('No stat found for %s in %s (found %s)' %
55 (path, dir_path, dir_stat.child_versions)) 55 (path, dir_path, dir_stat.child_versions))
56 return StatInfo(file_version) 56 return StatInfo(file_version)
57 57
58 dir_stat = self._stat_object_store.Get(dir_path).Get() 58 dir_stat = self._stat_object_store.Get(dir_path).Get()
59 if dir_stat is not None: 59 if dir_stat is not None:
60 return Future(value=make_stat_info(dir_stat)) 60 return Future(callback=lambda: make_stat_info(dir_stat))
61 61
62 def next(dir_stat): 62 def next(dir_stat):
63 assert dir_stat is not None # should have raised a FileNotFoundError 63 assert dir_stat is not None # should have raised a FileNotFoundError
64 # We only ever need to cache the dir stat. 64 # We only ever need to cache the dir stat.
65 self._stat_object_store.Set(dir_path, dir_stat) 65 self._stat_object_store.Set(dir_path, dir_stat)
66 return make_stat_info(dir_stat) 66 return make_stat_info(dir_stat)
67 return self._MemoizedStatAsyncFromFileSystem(dir_path).Then(next) 67 return self._MemoizedStatAsyncFromFileSystem(dir_path).Then(next)
68 68
69 @memoize 69 @memoize
70 def _MemoizedStatAsyncFromFileSystem(self, dir_path): 70 def _MemoizedStatAsyncFromFileSystem(self, dir_path):
71 '''This is a simple wrapper to memoize Futures to directory stats, since 71 '''This is a simple wrapper to memoize Futures to directory stats, since
72 StatAsync makes heavy use of it. Only cache directories so that the 72 StatAsync makes heavy use of it. Only cache directories so that the
73 memoized cache doesn't blow up. 73 memoized cache doesn't blow up.
74 ''' 74 '''
75 assert IsDirectory(dir_path) 75 assert IsDirectory(dir_path)
76 return self._file_system.StatAsync(dir_path) 76 return self._file_system.StatAsync(dir_path)
77 77
78 def Read(self, paths, skip_not_found=False): 78 def Read(self, paths, skip_not_found=False):
79 '''Reads a list of files. If a file is in memcache and it is not out of 79 '''Reads a list of files. If a file is cached and it is not out of
80 date, it is returned. Otherwise, the file is retrieved from the file system. 80 date, it is returned. Otherwise, the file is retrieved from the file system.
81 ''' 81 '''
82 # Files which aren't found are cached in the read object store as
83 # (path, None, None). This is to prevent re-reads of files we know
84 # do not exist.
82 cached_read_values = self._read_object_store.GetMulti(paths).Get() 85 cached_read_values = self._read_object_store.GetMulti(paths).Get()
83 cached_stat_values = self._stat_object_store.GetMulti(paths).Get() 86 cached_stat_values = self._stat_object_store.GetMulti(paths).Get()
84 87
85 # Populate a map of paths to Futures to their stat. They may have already 88 # Populate a map of paths to Futures to their stat. They may have already
86 # been cached in which case their Future will already have been constructed 89 # been cached in which case their Future will already have been constructed
87 # with a value. 90 # with a value.
88 stat_futures = {} 91 stat_futures = {}
89 92
90 def handle(error): 93 def handle(error):
91 if isinstance(error, FileNotFoundError): 94 if isinstance(error, FileNotFoundError):
92 return None 95 return None
93 raise error 96 raise error
94 97
95 for path in paths: 98 for path in paths:
96 stat_value = cached_stat_values.get(path) 99 stat_value = cached_stat_values.get(path)
97 if stat_value is None: 100 if stat_value is None:
98 stat_future = self.StatAsync(path) 101 stat_future = self.StatAsync(path)
99 if skip_not_found: 102 if skip_not_found:
100 stat_future = stat_future.Then(lambda x: x, handle) 103 stat_future = stat_future.Then(lambda x: x, handle)
101 else: 104 else:
102 stat_future = Future(value=stat_value) 105 stat_future = Future(value=stat_value)
103 stat_futures[path] = stat_future 106 stat_futures[path] = stat_future
104 107
105 # Filter only the cached data which is fresh by comparing to the latest 108 # Filter only the cached data which is up to date by comparing to the latest
106 # stat. The cached read data includes the cached version. Remove it for 109 # stat. The cached read data includes the cached version. Remove it for
107 # the result returned to callers. 110 # the result returned to callers. |version| == None implies a non-existent
108 fresh_data = dict( 111 # file, so skip it.
112 up_to_date_data = dict(
109 (path, data) for path, (data, version) in cached_read_values.iteritems() 113 (path, data) for path, (data, version) in cached_read_values.iteritems()
110 if stat_futures[path].Get().version == version) 114 if version is not None and stat_futures[path].Get().version == version)
111 115
112 if len(fresh_data) == len(paths): 116 if skip_not_found:
117 # Filter out paths which we know do not exist, i.e. if |path| is in
118 # |cached_read_values| *and* has a None version, then it doesn't exist.
119 # See the above declaration of |cached_read_values| for more information.
120 paths = [path for path in paths
121 if cached_read_values.get(path, (None, True))[1]]
122
123 if len(up_to_date_data) == len(paths):
113 # Everything was cached and up-to-date. 124 # Everything was cached and up-to-date.
114 return Future(value=fresh_data) 125 return Future(value=up_to_date_data)
115 126
116 def next(new_results): 127 def next(new_results):
117 # Update the cache. This is a path -> (data, version) mapping. 128 # Update the cache. This is a path -> (data, version) mapping.
118 self._read_object_store.SetMulti( 129 self._read_object_store.SetMulti(
119 dict((path, (new_result, stat_futures[path].Get().version)) 130 dict((path, (new_result, stat_futures[path].Get().version))
120 for path, new_result in new_results.iteritems())) 131 for path, new_result in new_results.iteritems()))
121 new_results.update(fresh_data) 132 # Update the read cache to include files that weren't found, to prevent
133 # constantly trying to read a file we now know doesn't exist.
134 self._read_object_store.SetMulti(
135 dict((path, (None, None)) for path in paths
136 if stat_futures[path].Get() is None))
137 new_results.update(up_to_date_data)
122 return new_results 138 return new_results
123 # Read in the values that were uncached or old. 139 # Read in the values that were uncached or old.
124 return self._file_system.Read(set(paths) - set(fresh_data.iterkeys()), 140 return self._file_system.Read(set(paths) - set(up_to_date_data.iterkeys()),
125 skip_not_found=skip_not_found).Then(next) 141 skip_not_found=skip_not_found).Then(next)
126 142
127 def GetIdentity(self): 143 def GetIdentity(self):
128 return self._file_system.GetIdentity() 144 return self._file_system.GetIdentity()
129 145
130 def __repr__(self): 146 def __repr__(self):
131 return '%s of <%s>' % (type(self).__name__, repr(self._file_system)) 147 return '%s of <%s>' % (type(self).__name__, repr(self._file_system))
OLDNEW
« no previous file with comments | « chrome/common/extensions/docs/server2/app.yaml ('k') | chrome/common/extensions/docs/server2/caching_file_system_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698