summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Coldrick <adam.coldrick@codethink.co.uk>2015-01-22 10:58:53 +0000
committerAdam Coldrick <adam.coldrick@codethink.co.uk>2015-01-23 10:03:15 +0000
commit854983f275dd6b6f3f8185403f4a618e8bad8c81 (patch)
tree55def9262ec5e8f7a86c112376feb12379bd8f2b
parent25b98cf567ba8faf1f717677cb1f9da2292c22dc (diff)
downloadmorph-854983f275dd6b6f3f8185403f4a618e8bad8c81.tar.gz
Add a cache manager utilising pylru and pickle
-rw-r--r--morphlib/sourceresolver.py51
1 files changed, 51 insertions, 0 deletions
diff --git a/morphlib/sourceresolver.py b/morphlib/sourceresolver.py
index d9ffd049..35f65729 100644
--- a/morphlib/sourceresolver.py
+++ b/morphlib/sourceresolver.py
@@ -17,11 +17,62 @@
import cliapp
import collections
+import cPickle
import logging
+import pylru
import morphlib
+class PickleCacheManager(object):
+ '''Cache manager for PyLRU that reads and writes to Pickle files.
+
+ The 'pickle' format is less than ideal in many ways and is actually
+ slower than JSON in Python. However, the data we need to cache is keyed
+ by tuples and in JSON a dict can only be keyed with strings. For now,
+ using 'pickle' seems to be the least worst option.
+
+ '''
+
+ def __init__(self, filename, size):
+ self.filename = filename
+ self.size = size
+
+ def _populate_cache_from_file(self, filename, cache):
+ try:
+ with open(filename, 'r') as f:
+ data = cPickle.load(f)
+ for key, value in data.iteritems():
+ cache[key] = value
+ except (EOFError, IOError, cPickle.PickleError) as e:
+ logging.warning('Failed to load cache %s: %s', self.filename, e)
+
+ def load_cache(self):
+ '''Create a pylru.lrucache object prepopulated with saved data.'''
+ cache = pylru.lrucache(self.size)
+ # There should be a more efficient way to do this, by hooking into
+ # the json module directly.
+ if os.path.exists(self.filename):
+ self._populate_cache_from_file(self.filename, cache)
+ return cache
+
+ def save_cache(self, cache):
+ '''Save the data from a pylru.lrucache object to disk.
+
+ Any changes that have been made by other instances or processes since
+ load_cache() was called will be overwritten.
+
+ '''
+ data = {}
+ for key, value in cache.items():
+ data[key] = value
+ try:
+ with open(self.filename, 'w') as f:
+ cPickle.dump(data, f)
+ except (IOError, cPickle.PickleError) as e:
+ logging.warning('Failed to save cache to %s: %s', self.filename, e)
+
+
class SourceResolverError(cliapp.AppException):
pass