-
Notifications
You must be signed in to change notification settings - Fork 0
/
ItemCache.py
executable file
·208 lines (169 loc) · 5.7 KB
/
ItemCache.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pickle
import os
import sys
from datetime import timedelta
import stat
import time
DEFAULT_CACHE_DIR = '~/.cache'
_debug = False
def _debug_msg(msg, eol = True):
if _debug:
if eol:
print('DEBUG:', msg)
else:
print('DEBUG:', msg, eol = '')
sys.stdout.flush()
class _ItemCacheIterator:
def __init__(self, keylist):
self.index = -1
self.keylist = keylist
def __iter__(self):
return self
def __next__(self):
self.index += 1
if len(self.keylist) > self.index:
return self.keylist[self.index]
else:
raise StopIteration()
class ItemCache(object):
def __init__(self, expiration = timedelta()):
if expiration is None:
self.exp = None
_debug_msg('Expiration of cache is switched off')
else:
try:
self.exp = expiration.total_seconds()
except:
# Do it in the python 2.6 way
self.exp = expiration.days * 86400 + expiration.seconds
_debug_msg('Setting expiration time to %s seconds' % self.exp)
### ItemCache interface to be implementd by child classes
def getItem(self, key):
raise KeyError(key)
def setItem(self, key, value):
raise KeyError(key)
def delItem(self, key):
raise KeyError(key)
def contains(self, key):
return False
def getKeys(self):
return list()
def expired(self, key):
raise KeyError(key)
### Define container interface
def __getitem__(self, key):
return self.getItem(key)
def __setitem__(self, key, value):
return self.setItem(key, value)
def __delitem__(self, key):
return self.delItem(key)
def __contains__(self, key):
return self.contains(key)
def __iter__(self):
return _ItemCacheIterator(self.getKeys())
def __len__(self):
return len(self.getKeys())
class ItemMemCache(ItemCache):
cache = {}
def __init__(self, expiration = timedelta()):
ItemCache.__init__(self, expiration)
def getItem(self, key):
return self.cache[str(key)]
def setItem(self, key, value):
self.cache[str(key)] = value
def delItem(self, key):
del self.cache[str(key)]
def contains(self, key):
return str(key) in self.cache
def getKeys(self):
return self.cache.keys()
def expired(self, key):
# Memory cache never expires
return False
class ItemDiskCache(ItemMemCache):
def __init__(self, cacheName = "", diskCacheDir = DEFAULT_CACHE_DIR, expiration = timedelta()):
ItemMemCache.__init__(self, expiration)
self.cacheName = cacheName
self.diskCacheDir = diskCacheDir
self.dirname = os.path.expanduser(diskCacheDir + '/' + cacheName.replace('/', '.'))
if not os.path.exists(self.dirname):
os.makedirs(self.dirname)
def _getItemPath(self, key):
key = "".join(i for i in key if ord(i)<128)
return self.dirname + '/' + str(key).replace('/', '.')
def expired(self, key):
if (self.exp is None) or (self.exp <= 0):
# Never expires
return False
item_path = self._getItemPath(key)
mtime = os.stat(item_path).st_mtime
return (mtime + self.exp) < time.time()
def getItem(self, key):
key = str(key)
value = None
try:
value = ItemMemCache.getItem(self, key)
except KeyError:
# The item has not be found in MemCache
# Lets try to found in DiskCache
item_path = self._getItemPath(key)
if os.path.exists(item_path) and not self.expired(key):
with open(item_path, 'rb') as f:
try:
value = pickle.load(f)
except:
# The cache is somehow corrupted; remove it
self.delItem(key)
raise KeyError('Disk Cache for item %s is corupted' % key)
else:
# Not found even in disk cache or is expired
raise KeyError(key)
# We have got the value from cache
return value
def setItem(self, key, value):
# Save it to MemCache first
ItemMemCache.setItem(self, key, value)
key = str(key)
item_path = self._getItemPath(key)
with open(item_path, 'wb') as f:
result = pickle.dump(value, f)
return result
def delItem(self, key):
key = str(key)
item_path = self._getItemPath(key)
os.remove(item_path)
def contains(self, key):
key = str(key)
item_path = self._getItemPath(key)
return (os.path.exists(item_path) and not self.expired(key))
def getKeys(self):
item_path = self._getItemPath('')
for (dirpath, dirnames, filenames) in os.walk(item_path):
return filenames
# Module testing
if __name__ == "__main__":
_debug = True
c = ItemDiskCache("ItemDiskCache", "/tmp", timedelta(days = 5))
try:
del c['blah']
del c['blah2']
except:
pass
c['blah'] = "Bubaq"
c['blah2'] = 'Bubaq2'
for k in c:
print('Key = %s, Value = %s' % (k, c[k]))
print('Is blah in cache: ', 'blah' in c)
if 'blah' in c:
print('Is blah expired: ', c.expired('blah'))
print('Is blah333 in cache: ', 'blah333' in c)
if 'blah333' in c:
print('Is blah333 expired: ', c.expired('blah333'))
del c['blah']
del c['blah2']
try:
del c['blah333']
except:
print('Key blah333 does not exists in the cache')