last plc-dependent code moved to PlDriver
[sfa.git] / sfa / util / cache.py
1 #
2 # This module implements general purpose caching system
3 #
4 from __future__ import with_statement
5 import time
6 import threading
7 import pickle
8 from datetime import datetime
9
10 # maximum lifetime of cached data (in seconds) 
11 DEFAULT_CACHE_TTL = 60 * 60
12
13 class CacheData:
14
15     data = None
16     created = None
17     expires = None
18     lock = None
19
20     def __init__(self, data, ttl = DEFAULT_CACHE_TTL):
21         self.lock = threading.RLock()
22         self.data = data
23         self.renew(ttl)
24
25     def is_expired(self):
26         return time.time() > self.expires
27
28     def get_created_date(self):
29         return str(datetime.fromtimestamp(self.created))
30
31     def get_expires_date(self):
32         return str(datetime.fromtimestamp(self.expires))
33
34     def renew(self, ttl = DEFAULT_CACHE_TTL):
35         self.created = time.time()
36         self.expires = self.created + ttl   
37        
38     def set_data(self, data, renew=True, ttl = DEFAULT_CACHE_TTL):
39         with self.lock: 
40             self.data = data
41             if renew:
42                 self.renew(ttl)
43     
44     def get_data(self):
45         return self.data
46
47
48     def dump(self):
49         return self.__dict__
50
51     def __str__(self):
52         return str(self.dump())  
53         
54     def tostring(self):
55         return self.__str__()
56
57     def __getstate__(self):
58         d = dict(self.__dict__)
59         del d['lock']
60         return d
61
62     def __setstate__(self, d):
63         self.__dict__.update(d)
64         self.lock = threading.RLock()
65         
66
67 class Cache:
68
69     cache  = {}
70     lock = threading.RLock()
71
72     def __init__(self, filename=None):
73         if filename:
74             self.load_from_file(filename)
75    
76     def add(self, key, value, ttl = DEFAULT_CACHE_TTL):
77         with self.lock:
78             if self.cache.has_key(key):
79                 self.cache[key].set_data(value, ttl=ttl)
80             else:
81                 self.cache[key] = CacheData(value, ttl)
82            
83     def get(self, key):
84         data = self.cache.get(key)
85         if not data:  
86             data = None
87         elif data.is_expired():
88             self.pop(key)
89             data = None 
90         else:
91             data = data.get_data()
92         return data
93
94     def pop(self, key):
95         if key in self.cache:
96             self.cache.pop(key) 
97
98     def dump(self):
99         result = {}
100         for key in self.cache:
101             result[key] = self.cache[key].__getstate__()
102         return result
103
104     def __str__(self):
105         return str(self.dump())     
106  
107     def tostring(self):
108         return self.__str()    
109
110     def save_to_file(self, filename):
111         f = open(filename, 'w')
112         pickle.dump(self.cache, f)
113
114     def load_from_file(self, filename):
115         f = open(filename, 'r')
116         self.cache = pickle.load(f)