ac6d18463c540ad2af84d3b76a9db2129cfa333e
[arvados.git] / sdk / python / arvados / cache.py
1 import errno
2 import md5
3 import os
4 import tempfile
5 import time
6
7 class SafeHTTPCache(object):
8     """Thread-safe replacement for httplib2.FileCache"""
9
10     def __init__(self, path=None, max_age=None):
11         self._dir = path
12         if max_age is not None:
13             try:
14                 self._clean(threshold=time.time() - max_age)
15             except:
16                 pass
17
18     def _clean(self, threshold=0):
19         for ent in os.listdir(self._dir):
20             fnm = os.path.join(self._dir, ent)
21             if os.path.isdir(fnm) or not fnm.endswith('.tmp'):
22                 continue
23             stat = os.lstat(fnm)
24             if stat.st_mtime < threshold:
25                 try:
26                     os.unlink(fnm)
27                 except OSError as err:
28                     if err.errno != errno.ENOENT:
29                         raise
30
31     def __str__(self):
32         return self._dir
33
34     def _filename(self, url):
35         return os.path.join(self._dir, md5.new(url).hexdigest()+'.tmp')
36
37     def get(self, url):
38         filename = self._filename(url)
39         try:
40             with open(filename, 'rb') as f:
41                 return f.read()
42         except IOError as OSError:
43             return None
44
45     def set(self, url, content):
46         try:
47             fd, tempname = tempfile.mkstemp(dir=self._dir)
48         except:
49             return None
50         try:
51             try:
52                 f = os.fdopen(fd, 'w')
53             except:
54                 os.close(fd)
55                 raise
56             try:
57                 f.write(content)
58             finally:
59                 f.close()
60             os.rename(tempname, self._filename(url))
61             tempname = None
62         finally:
63             if tempname:
64                 os.unlink(tempname)
65
66     def delete(self, url):
67         try:
68             os.unlink(self._filename(url))
69         except OSError as err:
70             if err.errno != errno.ENOENT:
71                 raise