File: papercut_cache.py

package info (click to toggle)
papercut 0.9.13-4
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 396 kB
  • ctags: 496
  • sloc: python: 4,872; xml: 105; sh: 71; makefile: 49; sql: 48
file content (92 lines) | stat: -rw-r--r-- 2,999 bytes parent folder | download | duplicates (2)
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
# 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 os.path
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 os.path.join(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