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

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

Issue 660383002: Docserver: Persist stat cache for versioned file systems (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 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 All, Future 9 from future import All, Future
10 from path_util import AssertIsDirectory, IsDirectory, ToDirectory 10 from path_util import AssertIsDirectory, IsDirectory, ToDirectory
11 from third_party.json_schema_compiler.memoize import memoize 11 from third_party.json_schema_compiler.memoize import memoize
12 12
13 13
14 class CachingFileSystem(FileSystem): 14 class CachingFileSystem(FileSystem):
15 '''FileSystem which implements a caching layer on top of |file_system|. It's 15 '''FileSystem which implements a caching layer on top of |file_system|. It's
16 smart, using Stat() to decided whether to skip Read()ing from |file_system|, 16 smart, using Stat() to decided whether to skip Read()ing from |file_system|,
17 and only Stat()ing directories never files. 17 and only Stat()ing directories never files. If |fail_on_miss| is True, then
18 stat cache misses are treated like FileNotFound, rather than falling back onto
19 the underlying filesystem.
18 ''' 20 '''
19 def __init__(self, file_system, object_store_creator): 21 def __init__(self, file_system, object_store_creator, fail_on_miss=False):
20 self._file_system = file_system 22 self._file_system = file_system
23 self._fail_on_miss = fail_on_miss
21 def create_object_store(category, **optargs): 24 def create_object_store(category, **optargs):
22 return object_store_creator.Create( 25 return object_store_creator.Create(
23 CachingFileSystem, 26 CachingFileSystem,
24 category='%s/%s' % (file_system.GetIdentity(), category), 27 category='%s/%s' % (file_system.GetIdentity(), category),
25 **optargs) 28 **optargs)
26 self._stat_cache = create_object_store('stat') 29 self._stat_cache = create_object_store('stat', start_empty=False)
27 # The read caches can start populated (start_empty=False) because file 30 # The read caches can start populated (start_empty=False) because file
28 # updates are picked up by the stat, so it doesn't need the force-refresh 31 # updates are picked up by the stat, so it doesn't need the force-refresh
29 # which starting empty is designed for. Without this optimisation, cron 32 # which starting empty is designed for. Without this optimisation, cron
30 # runs are extra slow. 33 # runs are extra slow.
31 self._read_cache = create_object_store('read', start_empty=False) 34 self._read_cache = create_object_store('read', start_empty=False)
32 self._walk_cache = create_object_store('walk', start_empty=False) 35 self._walk_cache = create_object_store('walk', start_empty=False)
33 36
34 def Refresh(self): 37 def Refresh(self):
35 return self._file_system.Refresh() 38 return self._file_system.Refresh()
36 39
(...skipping 12 matching lines...) Expand all
49 ''' 52 '''
50 if path == dir_path: 53 if path == dir_path:
51 return dir_stat 54 return dir_stat
52 # Was a file stat. Extract that file. 55 # Was a file stat. Extract that file.
53 file_version = dir_stat.child_versions.get(file_path) 56 file_version = dir_stat.child_versions.get(file_path)
54 if file_version is None: 57 if file_version is None:
55 raise FileNotFoundError('No stat found for %s in %s (found %s)' % 58 raise FileNotFoundError('No stat found for %s in %s (found %s)' %
56 (path, dir_path, dir_stat.child_versions)) 59 (path, dir_path, dir_stat.child_versions))
57 return StatInfo(file_version) 60 return StatInfo(file_version)
58 61
62 def raise_not_found(path):
63 raise FileNotFoundError('Got 404 when stat\'ing %s' % path)
not at google - send to devlin 2014/10/20 21:06:57 It might complicate things for callers - but can w
Ken Rockot(use gerrit already) 2014/10/22 03:19:54 Will do, but it will take longer to sort that out.
64
59 dir_stat = self._stat_cache.Get(dir_path).Get() 65 dir_stat = self._stat_cache.Get(dir_path).Get()
60 if dir_stat is not None: 66 if dir_stat is not None:
61 return Future(callback=lambda: make_stat_info(dir_stat)) 67 return Future(callback=lambda: make_stat_info(dir_stat))
62 68
69 if self._fail_on_miss:
70 return Future(callback=lambda: raise_not_found(dir_path))
71
63 def next(dir_stat): 72 def next(dir_stat):
64 assert dir_stat is not None # should have raised a FileNotFoundError 73 assert dir_stat is not None # should have raised a FileNotFoundError
65 # We only ever need to cache the dir stat. 74 # We only ever need to cache the dir stat.
66 self._stat_cache.Set(dir_path, dir_stat) 75 self._stat_cache.Set(dir_path, dir_stat)
67 return make_stat_info(dir_stat) 76 return make_stat_info(dir_stat)
68 return self._MemoizedStatAsyncFromFileSystem(dir_path).Then(next) 77 return self._MemoizedStatAsyncFromFileSystem(dir_path).Then(next)
69 78
70 @memoize 79 @memoize
71 def _MemoizedStatAsyncFromFileSystem(self, dir_path): 80 def _MemoizedStatAsyncFromFileSystem(self, dir_path):
72 '''This is a simple wrapper to memoize Futures to directory stats, since 81 '''This is a simple wrapper to memoize Futures to directory stats, since
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 for f in self.ReadSingle(root).Get(): 171 for f in self.ReadSingle(root).Get():
163 if IsDirectory(f): 172 if IsDirectory(f):
164 dirs.append(f) 173 dirs.append(f)
165 else: 174 else:
166 files.append(f) 175 files.append(f)
167 # Update the cache. This is a root -> (dirs, files, version) mapping. 176 # Update the cache. This is a root -> (dirs, files, version) mapping.
168 self._walk_cache.Set(root, (dirs, files, root_stat.version)) 177 self._walk_cache.Set(root, (dirs, files, root_stat.version))
169 return dirs, files 178 return dirs, files
170 return self._file_system.Walk(root, depth=depth, file_lister=file_lister) 179 return self._file_system.Walk(root, depth=depth, file_lister=file_lister)
171 180
172 def GetCommitID(self):
173 return self._file_system.GetCommitID()
174
175 def GetPreviousCommitID(self):
176 return self._file_system.GetPreviousCommitID()
177
178 def GetIdentity(self): 181 def GetIdentity(self):
179 return self._file_system.GetIdentity() 182 return self._file_system.GetIdentity()
180 183
181 def __repr__(self): 184 def __repr__(self):
182 return '%s of <%s>' % (type(self).__name__, repr(self._file_system)) 185 return '%s of <%s>' % (type(self).__name__, repr(self._file_system))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698