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

Side by Side Diff: appengine/findit/common/cache_decorator.py

Issue 2456603003: [Predator] Add local cache for get command output. (Closed)
Patch Set: Fix mock file test. Created 4 years, 1 month 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
« no previous file with comments | « no previous file | appengine/findit/common/repo_util.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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('~'),
50 '.culprit_finder', 'local_cache')
51
47 52
48 class Cacher(object): 53 class Cacher(object):
49 """An interface to cache and retrieve data. 54 """An interface to cache and retrieve data.
50 55
51 Subclasses should implement the Get/Set functions. 56 Subclasses should implement the Get/Set functions.
52 TODO: Add a Delete function (default to no-op) if needed later. 57 TODO: Add a Delete function (default to no-op) if needed later.
53 """ 58 """
54 def Get(self, key): 59 def Get(self, key):
55 """Returns the cached data for the given key if available. 60 """Returns the cached data for the given key if available.
56 61
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 num += 1 131 num += 1
127 132
128 all_data[key] = _CachedItemMetaData(num) 133 all_data[key] = _CachedItemMetaData(num)
129 else: 134 else:
130 all_data[key] = compressed_data 135 all_data[key] = compressed_data
131 136
132 keys_not_set = memcache.set_multi(all_data, time=expire_time) 137 keys_not_set = memcache.set_multi(all_data, time=expire_time)
133 return len(keys_not_set) == 0 138 return len(keys_not_set) == 0
134 139
135 140
141 class LocalCacher(Cacher):
142 """Cacher that uses local files to cache data."""
143
144 lock = threading.Lock()
145
146 def __init__(self, cache_dir=_DEFAULT_LOCAL_CACHE_DIR):
stgao 2016/11/02 02:15:07 Can we avoid the default value, and let client pas
Sharu Jiang 2016/11/08 01:17:12 Done.
147 self.cache_dir = cache_dir
148 if not os.path.exists(cache_dir): # pragma: no cover.
149 os.makedirs(cache_dir)
150
151 def Get(self, key):
152 with LocalCacher.lock:
153 path = os.path.join(self.cache_dir, key)
154 if not os.path.exists(path):
155 return None
156
157 try:
158 with open(path) as f:
159 return pickle.loads(zlib.decompress(f.read()))
160 except Exception as e: # pragma: no cover.
161 logging.error('Failed loading cache: %s', e)
162 return None
163
164 def Set(self, key, data): # pylint: disable=W
165 with LocalCacher.lock:
166 try:
167 with open(os.path.join(self.cache_dir, key), 'wb') as f:
168 f.write(zlib.compress(pickle.dumps(data)))
169 except Exception as e: # pragma: no cover.
170 logging.error('Failed setting cache for key %s: %s', key, e)
171
172
136 def _DefaultKeyGenerator(func, args, kwargs): 173 def _DefaultKeyGenerator(func, args, kwargs):
137 """Generates a key from the function and arguments passed to it. 174 """Generates a key from the function and arguments passed to it.
138 175
139 Args: 176 Args:
140 func (function): An arbitrary function. 177 func (function): An arbitrary function.
141 args (list): Positional arguments passed to ``func``. 178 args (list): Positional arguments passed to ``func``.
142 kwargs (dict): Keyword arguments passed to ``func``. 179 kwargs (dict): Keyword arguments passed to ``func``.
143 180
144 Returns: 181 Returns:
145 A string to represent a call to the given function with the given arguments. 182 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
219 except Exception: # pragma: no cover. 256 except Exception: # pragma: no cover.
220 logging.exception( 257 logging.exception(
221 'Failed to cache data for function %s.%s, args=%s, kwargs=%s', 258 'Failed to cache data for function %s.%s, args=%s, kwargs=%s',
222 func.__module__, func.__name__, repr(args), repr(kwargs)) 259 func.__module__, func.__name__, repr(args), repr(kwargs))
223 260
224 return result 261 return result
225 262
226 return Wrapped 263 return Wrapped
227 264
228 return Decorator 265 return Decorator
OLDNEW
« no previous file with comments | « no previous file | appengine/findit/common/repo_util.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698