Package entropy :: Module cache

Source Code for Module entropy.cache

  1  # -*- coding: utf-8 -*- 
  2  ''' 
  3      # DESCRIPTION: 
  4      # Entropy Object Oriented Interface 
  5   
  6      Copyright (C) 2007-2009 Fabio Erculiani 
  7   
  8      This program is free software; you can redistribute it and/or modify 
  9      it under the terms of the GNU General Public License as published by 
 10      the Free Software Foundation; either version 2 of the License, or 
 11      (at your option) any later version. 
 12   
 13      This program is distributed in the hope that it will be useful, 
 14      but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16      GNU General Public License for more details. 
 17   
 18      You should have received a copy of the GNU General Public License 
 19      along with this program; if not, write to the Free Software 
 20      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 21  ''' 
 22  # pylint ~ ok 
 23   
 24  from __future__ import with_statement 
 25  from entropy.core import Singleton 
 26  from entropy.misc import TimeScheduled, Lifo 
 27  import time 
 28   
29 -class EntropyCacher(Singleton):
30 """ 31 Entropy asynchronous and synchronous cache writer 32 and reader. This class is a Singleton and contains 33 a thread doing the cache writes asynchronously, thus 34 it must be stopped before your application is terminated 35 calling the stop() method. 36 """ 37 38 import entropy.dump as dumpTools 39 import entropy.tools as entropyTools 40 import copy 41
42 - def init_singleton(self):
43 """ 44 Singleton overloaded method. Equals to __init__. 45 This is the place where all the properties initialization 46 takes place. 47 """ 48 import threading 49 self.__alive = False 50 self.__cache_writer = None 51 self.__cache_buffer = Lifo() 52 self.__cache_lock = threading.Lock()
53
54 - def __copy_obj(self, obj):
55 """ 56 Return a copy of an object done by the standard 57 library "copy" module. 58 59 @param obj: object to copy 60 @type obj: any Python object 61 @rtype: copied object 62 @return: copied object 63 """ 64 return self.copy.deepcopy(obj)
65
66 - def __cacher(self):
67 """ 68 This is where the actual asynchronous copy takes 69 place. __cacher runs on a different threads and 70 all the operations done by this are atomic and 71 thread-safe. It just loops over and over until 72 __alive becomes False. 73 """ 74 while 1: 75 if not self.__alive: 76 break 77 with self.__cache_lock: 78 data = self.__cache_buffer.pop() 79 if data == None: 80 break 81 key, data = data 82 d_o = self.dumpTools.dumpobj 83 if not d_o: 84 break 85 d_o(key, data)
86
87 - def __del__(self):
88 self.stop()
89
90 - def start(self):
91 """ 92 This is the method used to start the asynchronous cache 93 writer but also the whole cacher. If this method is not 94 called, the instance will always trash and cache write 95 request. 96 97 @return: None 98 """ 99 with self.__cache_lock: 100 self.__cache_buffer.clear() 101 self.__cache_writer = TimeScheduled(1, self.__cacher) 102 self.__cache_writer.set_delay_before(True) 103 self.__cache_writer.start() 104 while not self.__cache_writer.isAlive(): 105 continue 106 self.__alive = True
107
108 - def is_started(self):
109 """ 110 Return whether start is called or not. This equals to 111 checking if the cacher is running, thus is writing cache 112 to disk. 113 114 @return: None 115 """ 116 return self.__alive
117
118 - def stop(self):
119 """ 120 This method stops the execution of the cacher, which won't 121 accept cache writes anymore. The thread responsible of writing 122 to disk is stopped here and the Cacher will be back to being 123 inactive. A watchdog will avoid the thread to freeze the 124 call if the write buffer is overloaded. 125 126 @return: None 127 """ 128 129 self.__alive = False 130 watch_dog = 20 131 while self.__cache_buffer.is_filled() and (watch_dog > 0): 132 watch_dog -= 1 133 time.sleep(0.5) 134 135 with self.__cache_lock: 136 self.__cache_buffer.clear() 137 if self.__cache_writer != None: 138 self.__cache_writer.kill() 139 self.__cache_writer.join() 140 self.__cache_writer = None
141
142 - def sync(self, wait = False):
143 """ 144 This method can be called anytime and forces the instance 145 to flush all the cache writes queued to disk. If wait == False 146 a watchdog prevents this call to get stuck in case of write 147 buffer overloads. 148 149 @param wait: indicates if waiting until done (synchronous mode) 150 or not 151 @type wait: bool 152 153 @return: None 154 """ 155 if not self.__alive: 156 self.__cache_buffer.clear() 157 return 158 159 watch_dog = 10 160 while self.__cache_buffer.is_filled() and ((watch_dog > 0) or wait) \ 161 and self.__alive: 162 163 if not wait: 164 watch_dog -= 1 165 time.sleep(0.5) 166 167 self.__cache_buffer.clear()
168
169 - def discard(self):
170 """ 171 This method makes buffered cache to be discarded synchronously. 172 173 @return: None 174 """ 175 self.__cache_buffer.clear() 176 with self.__cache_lock: 177 self.__cache_buffer.clear() # make sure twice
178
179 - def push(self, key, data, async = True):
180 """ 181 This is the place where data is either added 182 to the write queue or written to disk (if async == False) 183 only and only if start() method has been called. 184 185 @param key: cache data identifier 186 @type key: basestring 187 @param data: picklable object 188 @type data: any picklable object 189 @param async: store cache asynchronously or not 190 @type async: bool 191 @rtype: None 192 @return: nothing 193 """ 194 if not self.__alive: 195 return 196 if async: 197 with self.__cache_lock: 198 self.__cache_buffer.push((key, self.__copy_obj(data),)) 199 else: 200 self.dumpTools.dumpobj(key, data)
201
202 - def pop(self, key):
203 """ 204 This is the place where data is retrieved from cache. 205 You must know the cache identifier used when push() 206 was called. 207 208 @param key: cache data identifier 209 @type key: basestring 210 @rtype: Python object 211 @return: object stored into the stack or None (if stack is empty) 212 """ 213 with self.__cache_lock: 214 l_o = self.dumpTools.loadobj 215 if not l_o: 216 return 217 return l_o(key)
218