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

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

Issue 521453003: Docserver: Override Walk in CachingFileSystem (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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 sys 5 import sys
6 6
7 import schema_util 7 import schema_util
8 from docs_server_utils import ToUnicode 8 from docs_server_utils import ToUnicode
9 from file_system import FileNotFoundError 9 from file_system import FileNotFoundError
10 from future import Future 10 from future import Future
11 from path_util import AssertIsDirectory, AssertIsFile, ToDirectory 11 from path_util import AssertIsDirectory, AssertIsFile, ToDirectory
12 from third_party.json_schema_compiler import json_parse 12 from third_party.json_schema_compiler import json_parse
13 from third_party.json_schema_compiler.memoize import memoize 13 from third_party.json_schema_compiler.memoize import memoize
14 from third_party.motemplate import Motemplate 14 from third_party.motemplate import Motemplate
15 15
16 16
17 _CACHEABLE_FUNCTIONS = set()
17 _SINGLE_FILE_FUNCTIONS = set() 18 _SINGLE_FILE_FUNCTIONS = set()
18 19
19 20
21 def _GetUnboundFunction(fn):
22 '''Functions bound to an object are separate from the unbound
ahernandez 2014/08/29 01:49:42 I don't know how to explain this concisely, but th
not at google - send to devlin 2014/08/29 05:00:14 Neat, nice catch. This nested decorator stuff in P
23 defintion. This causes issues when checking for membership,
24 so always get the unbound function, if possible.
25 '''
26 return getattr(fn, 'im_func', fn)
27
28
29 def Cache(fn):
30 '''A decorator which can be applied to the compilation function
31 passed to CompiledFileSystem.Create, indicating that file/list data
32 should be cached.
33
34 This decorator should be listed first in any list of decorators, along
35 with the SingleFile decorator below.
36 '''
37 _CACHEABLE_FUNCTIONS.add(_GetUnboundFunction(fn))
38 return fn
39
40
20 def SingleFile(fn): 41 def SingleFile(fn):
21 '''A decorator which can be optionally applied to the compilation function 42 '''A decorator which can be optionally applied to the compilation function
22 passed to CompiledFileSystem.Create, indicating that the function only 43 passed to CompiledFileSystem.Create, indicating that the function only
23 needs access to the file which is given in the function's callback. When 44 needs access to the file which is given in the function's callback. When
24 this is the case some optimisations can be done. 45 this is the case some optimisations can be done.
25 46
26 Note that this decorator must be listed first in any list of decorators to 47 Note that this decorator must be listed first in any list of decorators to
27 have any effect. 48 have any effect.
28 ''' 49 '''
29 _SINGLE_FILE_FUNCTIONS.add(fn) 50 _SINGLE_FILE_FUNCTIONS.add(_GetUnboundFunction(fn))
30 return fn 51 return fn
31 52
32 53
33 def Unicode(fn): 54 def Unicode(fn):
34 '''A decorator which can be optionally applied to the compilation function 55 '''A decorator which can be optionally applied to the compilation function
35 passed to CompiledFileSystem.Create, indicating that the function processes 56 passed to CompiledFileSystem.Create, indicating that the function processes
36 the file's data as Unicode text. 57 the file's data as Unicode text.
37 ''' 58 '''
38 59
39 # The arguments passed to fn can be (self, path, data) or (path, data). In 60 # The arguments passed to fn can be (self, path, data) or (path, data). In
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 compilation_function, 114 compilation_function,
94 create_object_store('file'), 115 create_object_store('file'),
95 create_object_store('list')) 116 create_object_store('list'))
96 117
97 @memoize 118 @memoize
98 def ForJson(self, file_system): 119 def ForJson(self, file_system):
99 '''A CompiledFileSystem specifically for parsing JSON configuration data. 120 '''A CompiledFileSystem specifically for parsing JSON configuration data.
100 These are memoized over file systems tied to different branches. 121 These are memoized over file systems tied to different branches.
101 ''' 122 '''
102 return self.Create(file_system, 123 return self.Create(file_system,
103 SingleFile(lambda _, data: 124 Cache(SingleFile(lambda _, data:
not at google - send to devlin 2014/08/29 05:00:14 JSON should be ... fairly cheap? Very commonly use
104 json_parse.Parse(ToUnicode(data))), 125 json_parse.Parse(ToUnicode(data)))),
105 CompiledFileSystem, 126 CompiledFileSystem,
106 category='json') 127 category='json')
107 128
108 @memoize 129 @memoize
109 def ForTemplates(self, file_system): 130 def ForTemplates(self, file_system):
110 '''Creates a CompiledFileSystem for parsing templates. 131 '''Creates a CompiledFileSystem for parsing templates.
111 ''' 132 '''
112 return self.Create( 133 return self.Create(
113 file_system, 134 file_system,
114 SingleFile(lambda path, text: Motemplate(ToUnicode(text), name=path)), 135 SingleFile(lambda path, text: Motemplate(ToUnicode(text), name=path)),
(...skipping 12 matching lines...) Expand all
127 def __init__(self, 148 def __init__(self,
128 file_system, 149 file_system,
129 compilation_function, 150 compilation_function,
130 file_object_store, 151 file_object_store,
131 list_object_store): 152 list_object_store):
132 self._file_system = file_system 153 self._file_system = file_system
133 self._compilation_function = compilation_function 154 self._compilation_function = compilation_function
134 self._file_object_store = file_object_store 155 self._file_object_store = file_object_store
135 self._list_object_store = list_object_store 156 self._list_object_store = list_object_store
136 157
158 def _GetFromStore(self, key, store):
159 if _GetUnboundFunction(self._compilation_function) in _CACHEABLE_FUNCTIONS:
160 return store.Get(key)
161 return Future(value=None)
162
163 def _SetToStore(self, key, value, store):
164 if _GetUnboundFunction(self._compilation_function) in _CACHEABLE_FUNCTIONS:
165 store.Set(key, value)
166
167 def _GetFromFileStore(self, key):
168 return self._GetFromStore(key, self._file_object_store)
169
170 def _GetFromListStore(self, key):
171 return self._GetFromStore(key, self._list_object_store)
172
173 def _SetToFileStore(self, key, value):
174 self._SetToStore(key, value, self._file_object_store)
175
176 def _SetToListStore(self, key, value):
177 self._SetToStore(key, value, self._list_object_store)
178
137 def _RecursiveList(self, path): 179 def _RecursiveList(self, path):
138 '''Returns a Future containing the recursive directory listing of |path| as 180 '''Returns a Future containing the recursive directory listing of |path| as
139 a flat list of paths. 181 a flat list of paths.
140 ''' 182 '''
141 def split_dirs_from_files(paths): 183 def split_dirs_from_files(paths):
142 '''Returns a tuple (dirs, files) where |dirs| contains the directory 184 '''Returns a tuple (dirs, files) where |dirs| contains the directory
143 names in |paths| and |files| contains the files. 185 names in |paths| and |files| contains the files.
144 ''' 186 '''
145 result = [], [] 187 result = [], []
146 for path in paths: 188 for path in paths:
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 AssertIsFile(path) 234 AssertIsFile(path)
193 235
194 try: 236 try:
195 version = self._file_system.Stat(path).version 237 version = self._file_system.Stat(path).version
196 except FileNotFoundError: 238 except FileNotFoundError:
197 if skip_not_found: 239 if skip_not_found:
198 version = None 240 version = None
199 else: 241 else:
200 return Future(exc_info=sys.exc_info()) 242 return Future(exc_info=sys.exc_info())
201 243
202 cache_entry = self._file_object_store.Get(path).Get() 244 cache_entry = self._GetFromFileStore(path).Get()
not at google - send to devlin 2014/08/29 05:00:14 These wrapper functions are nice, but if you had s
203 if (cache_entry is not None) and (version == cache_entry.version): 245 if (cache_entry is not None) and (version == cache_entry.version):
204 return Future(value=cache_entry._cache_data) 246 return Future(value=cache_entry._cache_data)
205 247
206 def compile_(files): 248 def compile_(files):
207 cache_data = self._compilation_function(path, files) 249 cache_data = self._compilation_function(path, files)
208 self._file_object_store.Set(path, _CacheEntry(cache_data, version)) 250 self._SetToFileStore(path, _CacheEntry(cache_data, version))
not at google - send to devlin 2014/08/29 05:00:14 (FWIW I think that "set in" reads slightly better
209 return cache_data 251 return cache_data
210 252
211 return self._file_system.ReadSingle( 253 return self._file_system.ReadSingle(
212 path, skip_not_found=skip_not_found).Then(compile_) 254 path, skip_not_found=skip_not_found).Then(compile_)
213 255
214 def GetFromFileListing(self, path): 256 def GetFromFileListing(self, path):
215 '''Calls |compilation_function| on the listing of the files at |path|. 257 '''Calls |compilation_function| on the listing of the files at |path|.
216 Assumes that the path given is to a directory. 258 Assumes that the path given is to a directory.
217 ''' 259 '''
218 AssertIsDirectory(path) 260 AssertIsDirectory(path)
219 261
220 try: 262 try:
221 version = self._file_system.Stat(path).version 263 version = self._file_system.Stat(path).version
222 except FileNotFoundError: 264 except FileNotFoundError:
223 return Future(exc_info=sys.exc_info()) 265 return Future(exc_info=sys.exc_info())
224 266
225 cache_entry = self._list_object_store.Get(path).Get() 267 cache_entry = self._GetFromListStore(path).Get()
226 if (cache_entry is not None) and (version == cache_entry.version): 268 if (cache_entry is not None) and (version == cache_entry.version):
227 return Future(value=cache_entry._cache_data) 269 return Future(value=cache_entry._cache_data)
228 270
229 def next(files): 271 def next(files):
230 cache_data = self._compilation_function(path, files) 272 cache_data = self._compilation_function(path, files)
231 self._list_object_store.Set(path, _CacheEntry(cache_data, version)) 273 self._SetToListStore(path, _CacheEntry(cache_data, version))
232 return cache_data 274 return cache_data
233 return self._RecursiveList(path).Then(next) 275 return self._RecursiveList(path).Then(next)
234 276
235 def GetFileVersion(self, path): 277 def GetFileVersion(self, path):
236 cache_entry = self._file_object_store.Get(path).Get() 278 cache_entry = self._GetFromFileStore(path).Get()
237 if cache_entry is not None: 279 if cache_entry is not None:
238 return cache_entry.version 280 return cache_entry.version
239 return self._file_system.Stat(path).version 281 return self._file_system.Stat(path).version
240 282
241 def GetFileListingVersion(self, path): 283 def GetFileListingVersion(self, path):
242 path = ToDirectory(path) 284 path = ToDirectory(path)
243 cache_entry = self._list_object_store.Get(path).Get() 285 cache_entry = self._GetFromListStore(path).Get()
244 if cache_entry is not None: 286 if cache_entry is not None:
245 return cache_entry.version 287 return cache_entry.version
246 return self._file_system.Stat(path).version 288 return self._file_system.Stat(path).version
247 289
248 def FileExists(self, path): 290 def FileExists(self, path):
249 return self._file_system.Exists(path) 291 return self._file_system.Exists(path)
250 292
251 def GetIdentity(self): 293 def GetIdentity(self):
252 return self._file_system.GetIdentity() 294 return self._file_system.GetIdentity()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698