-
Notifications
You must be signed in to change notification settings - Fork 17
/
papercut_cache.py
executable file
·91 lines (76 loc) · 2.91 KB
/
papercut_cache.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
#!/usr/bin/env python
# Copyright (c) 2002 Joao Prado Maia. See the LICENSE file for more information.
# $Id: papercut_cache.py,v 1.7 2002-10-04 03:14:38 jpm Exp $
import binascii
import md5
import time
import os
import cPickle
import portable_locker
# papercut settings file
import settings
# methods that need to be cached
cache_methods = ('get_XHDR', 'get_XGTITLE', 'get_LISTGROUP',
'get_XPAT', 'get_XOVER', 'get_BODY',
'get_HEAD', 'get_ARTICLE', 'get_STAT',
'get_LIST')
class CallableWrapper:
name = None
thecallable = None
cacheable_methods = ()
def __init__(self, name, thecallable, cacheable_methods):
self.name = name
self.thecallable = thecallable
self.cacheable_methods = cacheable_methods
def __call__(self, *args, **kwds):
if self.name not in self.cacheable_methods:
return self.thecallable(*args, **kwds)
else:
filename = self._get_filename(*args, **kwds)
if os.path.exists(filename):
# check the expiration
expire, result = self._get_cached_result(filename)
diff = time.time() - expire
if diff > settings.nntp_cache_expire:
# remove the file and run the method again
return self._save_result(filename, *args, **kwds)
else:
return result
else:
return self._save_result(filename, *args, **kwds)
def _get_cached_result(self, filename):
inf = open(filename, 'rb')
# get a lock on the file
portable_locker.lock(inf, portable_locker.LOCK_SH)
expire = cPickle.load(inf)
result = cPickle.load(inf)
# release the lock
portable_locker.unlock(inf)
inf.close()
return (expire, result)
def _save_result(self, filename, *args, **kwds):
result = self.thecallable(*args, **kwds)
# save the serialized result in the file
outf = open(filename, 'w')
# file write lock
portable_locker.lock(outf, portable_locker.LOCK_EX)
cPickle.dump(time.time(), outf)
cPickle.dump(result, outf)
# release the lock
portable_locker.unlock(outf)
outf.close()
return result
def _get_filename(self, *args, **kwds):
arguments = '%s%s%s' % (self.name, args, kwds)
return '%s%s' % (settings.nntp_cache_path, binascii.hexlify(md5.new(arguments).digest()))
class Cache:
backend = None
cacheable_methods = ()
def __init__(self, storage_handle, cacheable_methods):
self.backend = storage_handle.Papercut_Storage()
self.cacheable_methods = cacheable_methods
def __getattr__(self, name):
result = getattr(self.backend, name)
if callable(result):
result = CallableWrapper(name, result, self.cacheable_methods)
return result