Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 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 """This module provides a decorator to cache the results of a function. | 5 """This module provides a decorator to cache the results of a function. |
| 6 | 6 |
| 7 Examples: | 7 Examples: |
| 8 1. Decorate a function: | 8 1. Decorate a function: |
| 9 @cache_decorator.Cached() | 9 @cache_decorator.Cached() |
| 10 def Test(a): | 10 def Test(a): |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 | 32 |
| 33 d2 = Downloader('http://url', 5) | 33 d2 = Downloader('http://url', 5) |
| 34 d2.Download('path') # Returned the cached downloaded data. | 34 d2.Download('path') # Returned the cached downloaded data. |
| 35 """ | 35 """ |
| 36 | 36 |
| 37 import cStringIO | 37 import cStringIO |
| 38 import functools | 38 import functools |
| 39 import hashlib | 39 import hashlib |
| 40 import inspect | 40 import inspect |
| 41 import logging | 41 import logging |
| 42 import os | |
| 42 import pickle | 43 import pickle |
| 44 import threading | |
| 43 import zlib | 45 import zlib |
| 44 | 46 |
| 45 from google.appengine.api import memcache | 47 from google.appengine.api import memcache |
| 46 | 48 |
| 49 _DEFAULT_LOCAL_CACHE_DIR = os.path.join(os.path.expanduser('~'), '.cache') | |
|
Martin Barbella
2016/10/26 23:21:20
This shouldn't use such a generic name. This will
wrengr
2016/10/27 16:36:47
Seconded.
Sharu Jiang
2016/10/27 21:59:05
Done. Use .culprit_finder/local_cache since it's s
| |
| 50 | |
| 47 | 51 |
| 48 class Cacher(object): | 52 class Cacher(object): |
|
wrengr
2016/10/27 16:36:47
Using "-er" names for classes is weird. Why not ju
Sharu Jiang
2016/10/27 21:59:05
I think it means 'Cacher' caches.
wrengr
2016/10/28 18:02:00
In all the communities I've programmed in, we don'
Sharu Jiang
2016/11/08 01:17:12
This make senses, added a todo.
| |
| 49 """An interface to cache and retrieve data. | 53 """An interface to cache and retrieve data. |
| 50 | 54 |
| 51 Subclasses should implement the Get/Set functions. | 55 Subclasses should implement the Get/Set functions. |
| 52 TODO: Add a Delete function (default to no-op) if needed later. | 56 TODO: Add a Delete function (default to no-op) if needed later. |
| 53 """ | 57 """ |
| 54 def Get(self, key): | 58 def Get(self, key): |
| 55 """Returns the cached data for the given key if available. | 59 """Returns the cached data for the given key if available. |
| 56 | 60 |
| 57 Args: | 61 Args: |
| 58 key (str): The key to identify the cached data. | 62 key (str): The key to identify the cached data. |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 126 num += 1 | 130 num += 1 |
| 127 | 131 |
| 128 all_data[key] = _CachedItemMetaData(num) | 132 all_data[key] = _CachedItemMetaData(num) |
| 129 else: | 133 else: |
| 130 all_data[key] = compressed_data | 134 all_data[key] = compressed_data |
| 131 | 135 |
| 132 keys_not_set = memcache.set_multi(all_data, time=expire_time) | 136 keys_not_set = memcache.set_multi(all_data, time=expire_time) |
| 133 return len(keys_not_set) == 0 | 137 return len(keys_not_set) == 0 |
| 134 | 138 |
| 135 | 139 |
| 140 class LocalCacher(object): | |
|
Martin Barbella
2016/10/26 23:21:20
Solely for the sake of consistency, it seems like
Sharu Jiang
2016/10/27 21:59:05
Oops, it should.
| |
| 141 """Cacher that uses local files to cache data.""" | |
| 142 | |
| 143 lock = threading.Lock() | |
| 144 | |
| 145 def __init__(self, cache_dir=_DEFAULT_LOCAL_CACHE_DIR): | |
| 146 self.cache_dir = cache_dir | |
| 147 if not os.path.exists(cache_dir): # pragma: no cover. | |
| 148 os.mkdir(cache_dir) | |
| 149 | |
| 150 def Get(self, key): | |
| 151 with LocalCacher.lock: | |
| 152 path = os.path.join(self.cache_dir, key) | |
| 153 if not os.path.exists(path): | |
| 154 return None | |
| 155 | |
| 156 try: | |
| 157 with open(path) as f: | |
| 158 return pickle.loads(zlib.decompress(f.read())) | |
| 159 except Exception: # pragma: no cover. | |
| 160 logging.error('Failed load cache.') | |
|
Martin Barbella
2016/10/26 23:21:20
Could you make this error a bit more descriptive,
Sharu Jiang
2016/10/27 21:59:05
Done.
| |
| 161 return None | |
| 162 | |
| 163 def Set(self, key, data): # pylint: disable=W | |
| 164 with LocalCacher.lock: | |
| 165 try: | |
| 166 with open(os.path.join(self.cache_dir, key), 'wb') as f: | |
| 167 f.write(zlib.compress(pickle.dumps(data))) | |
| 168 except Exception: # pragma: no cover. | |
| 169 logging.error('Failed to cache key %s', key) | |
| 170 | |
| 171 | |
| 136 def _DefaultKeyGenerator(func, args, kwargs): | 172 def _DefaultKeyGenerator(func, args, kwargs): |
| 137 """Generates a key from the function and arguments passed to it. | 173 """Generates a key from the function and arguments passed to it. |
| 138 | 174 |
| 139 Args: | 175 Args: |
| 140 func (function): An arbitrary function. | 176 func (function): An arbitrary function. |
| 141 args (list): Positional arguments passed to ``func``. | 177 args (list): Positional arguments passed to ``func``. |
| 142 kwargs (dict): Keyword arguments passed to ``func``. | 178 kwargs (dict): Keyword arguments passed to ``func``. |
| 143 | 179 |
| 144 Returns: | 180 Returns: |
| 145 A string to represent a call to the given function with the given arguments. | 181 A string to represent a call to the given function with the given arguments. |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 except Exception: # pragma: no cover. | 255 except Exception: # pragma: no cover. |
| 220 logging.exception( | 256 logging.exception( |
| 221 'Failed to cache data for function %s.%s, args=%s, kwargs=%s', | 257 'Failed to cache data for function %s.%s, args=%s, kwargs=%s', |
| 222 func.__module__, func.__name__, repr(args), repr(kwargs)) | 258 func.__module__, func.__name__, repr(args), repr(kwargs)) |
| 223 | 259 |
| 224 return result | 260 return result |
| 225 | 261 |
| 226 return Wrapped | 262 return Wrapped |
| 227 | 263 |
| 228 return Decorator | 264 return Decorator |
| OLD | NEW |