comparison src/memory/persistent.py @ 2182:087eec4c6c07

memory (persistent, sqlite): better private values handling + new LazyPersistentBinaryDict: - merged private values method handling in sqlite, and added a keys arguments to get only some keys - LazyPersistentBinaryDict allow to get values in database only when they are needed, saving memory for big data
author Goffi <goffi@goffi.org>
date Sun, 12 Mar 2017 19:33:17 +0100
parents 2daf7b4c6756
children ea41cf1e6d29
comparison
equal deleted inserted replaced
2181:968b0d13bcc7 2182:087eec4c6c07
26 pass 26 pass
27 27
28 28
29 class PersistentDict(object): 29 class PersistentDict(object):
30 r"""A dictionary which save persistently each value assigned 30 r"""A dictionary which save persistently each value assigned
31
31 /!\ be careful, each assignment means a database write 32 /!\ be careful, each assignment means a database write
32 /!\ Memory must be initialised before loading/setting value with instances of this class""" 33 /!\ Memory must be initialised before loading/setting value with instances of this class"""
33 storage = None 34 storage = None
35 binary = False
34 36
35 def __init__(self, namespace, profile=None): 37 def __init__(self, namespace, profile=None):
36 """@param namespace: unique namespace for this dictionary 38 """
37 @param profile: profile which *MUST* exists, or None for general values""" 39
40 @param namespace: unique namespace for this dictionary
41 @param profile(unicode, None): profile which *MUST* exists, or None for general values
42 """
38 if not self.storage: 43 if not self.storage:
39 log.error(_("PersistentDict can't be used before memory initialisation")) 44 log.error(_("PersistentDict can't be used before memory initialisation"))
40 raise MemoryNotInitializedError 45 raise MemoryNotInitializedError
41 self._cache = {} 46 self._cache = None
42 self.namespace = namespace 47 self.namespace = namespace
43 self.profile = profile 48 self.profile = profile
44 49
50 def _setCache(self, data):
51 self._cache = data
52
45 def load(self): 53 def load(self):
46 """Load persistent data from storage. 54 """Load persistent data from storage.
47 55
56 need to be called before any other operation
48 @return: defers the PersistentDict instance itself 57 @return: defers the PersistentDict instance itself
49 """ 58 """
50 if not self.profile: 59 d = self.storage.getPrivates(self.namespace, binary=self.binary, profile=self.profile)
51 d = self.storage.loadGenPrivates(self._cache, self.namespace) 60 d.addCallback(self._setCache)
52 else: 61 d.addCallback(lambda dummy: self)
53 d = self.storage.loadIndPrivates(self._cache, self.namespace, self.profile) 62 return d
54 return d.addCallback(lambda dummy: self)
55 63
56 def iteritems(self): 64 def iteritems(self):
57 return self._cache.iteritems() 65 return self._cache.iteritems()
58 66
59 def items(self): 67 def items(self):
100 108
101 def __getitem__(self, key): 109 def __getitem__(self, key):
102 return self._cache.__getitem__(key) 110 return self._cache.__getitem__(key)
103 111
104 def __setitem__(self, key, value): 112 def __setitem__(self, key, value):
105 if not self.profile: 113 self.storage.setPrivateValue(self.namespace, key, value, self.binary, self.profile)
106 self.storage.setGenPrivate(self.namespace, key, value)
107 else:
108 self.storage.setIndPrivate(self.namespace, key, value, self.profile)
109 return self._cache.__setitem__(key, value) 114 return self._cache.__setitem__(key, value)
110 115
111 def __delitem__(self, key): 116 def __delitem__(self, key):
112 if not self.profile: 117 self.storage.detPrivateValue(self.namepace, key, self.binary, self.profile)
113 self.storage.delGenPrivate(self.namespace, key)
114 else:
115 self.storage.delIndPrivate(self.namespace, key, self.profile)
116 return self._cache.__delitem__(key) 118 return self._cache.__delitem__(key)
117 119
118 def get(self, key, default=None): 120 def get(self, key, default=None):
119 return self._cache.get(key, default) 121 return self._cache.get(key, default)
120 122
125 self.__setitem__(key, default) 127 self.__setitem__(key, default)
126 return default 128 return default
127 129
128 def force(self, name): 130 def force(self, name):
129 """Force saving of an attribute to storage 131 """Force saving of an attribute to storage
130 @return: deferred fired when data is actually saved""" 132
131 if not self.profile: 133 @return: deferred fired when data is actually saved
132 return self.storage.setGenPrivate(self.namespace, name, self._cache[name]) 134 """
133 return self.storage.setIndPrivate(self.namespace, name, self._cache[name], self.profile) 135 return self.storage.setPrivateValue(self.namespace, name, self._cache[name], self.binary, self.profile)
134 136
135 137
136 class PersistentBinaryDict(PersistentDict): 138 class PersistentBinaryDict(PersistentDict):
137 """Persistent dict where value can be any python data (instead of string only)""" 139 """Persistent dict where value can be any python data (instead of string only)"""
140 binary = True
141
142
143 class LazyPersistentBinaryDict(PersistentBinaryDict):
144 ur"""PersistentBinaryDict which get key/value when needed
145
146 This Persistent need more database access, it is suitable for largest data,
147 to save memory.
148 /!\ most of methods return a Deferred
149 """
150 # TODO: missing methods should be implemented using database access
151 # TODO: a cache would be useful (which is deleted after a timeout)
138 152
139 def load(self): 153 def load(self):
140 """load persistent data from storage 154 # we show a warning as calling load on LazyPersistentBinaryDict sounds like a code mistake
141 """ 155 log.warning(_(u"Calling load on LazyPersistentBinaryDict while it's not needed"))
142 if not self.profile: 156
143 return self.storage.loadGenPrivatesBinary(self._cache, self.namespace) 157 def iteritems(self):
144 else: 158 raise NotImplementedError
145 return self.storage.loadIndPrivatesBinary(self._cache, self.namespace, self.profile) 159
160 def items(self):
161 return self.storage.getPrivates(self.namespace, binary=self.binary, profile=self.profile)
162
163 def __repr__(self):
164 raise NotImplementedError
165
166 def __str__(self):
167 return "LazyPersistentBinaryDict (namespace: {})".format(self.namespace)
168
169 def __lt__(self, other):
170 raise NotImplementedError
171
172 def __le__(self, other):
173 raise NotImplementedError
174
175 def __eq__(self, other):
176 raise NotImplementedError
177
178 def __ne__(self, other):
179 raise NotImplementedError
180
181 def __gt__(self, other):
182 raise NotImplementedError
183
184 def __ge__(self, other):
185 raise NotImplementedError
186
187 def __cmp__(self, other):
188 raise NotImplementedError
189
190 def __hash__(self):
191 return hash(unicode(self.__class__) + self.namespace + (self.profile or u''))
192
193 def __nonzero__(self):
194 raise NotImplementedError
195
196 def __contains__(self, key):
197 raise NotImplementedError
198
199 def __iter__(self):
200 raise NotImplementedError
201
202 def __getitem__(self, key):
203 """get the value as a Deferred"""
204 return self.storage.getPrivates(self.namespace, keys=[key], binary=self.binary, profile=self.profile)
146 205
147 def __setitem__(self, key, value): 206 def __setitem__(self, key, value):
148 if not self.profile: 207 self.storage.setPrivateValue(self.namespace, key, value, self.binary, self.profile)
149 self.storage.setGenPrivateBinary(self.namespace, key, value)
150 else:
151 self.storage.setIndPrivateBinary(self.namespace, key, value, self.profile)
152 return self._cache.__setitem__(key, value)
153 208
154 def __delitem__(self, key): 209 def __delitem__(self, key):
155 if not self.profile: 210 self.storage.detPrivateValue(self.namepace, key, self.binary, self.profile)
156 self.storage.delGenPrivateBinary(self.namespace, key) 211
157 else: 212 def _valueOrDefault(self, value, default):
158 self.storage.delIndPrivateBinary(self.namespace, key, self.profile) 213 if value is None:
159 return self._cache.__delitem__(key) 214 return default
160 215 return value
161 def force(self, name): 216
217 def get(self, key, default=None):
218 d = self.__getitem__(key)
219 d.addCallback(self._valueOrDefault)
220 return d
221
222 def setdefault(self, key, default):
223 raise NotImplementedError
224
225 def force(self, name, value):
162 """Force saving of an attribute to storage 226 """Force saving of an attribute to storage
163 @return: deferred fired when data is actually saved""" 227
164 if not self.profile: 228 @param value(object): value is needed for LazyPersistentBinaryDict
165 return self.storage.setGenPrivateBinary(self.namespace, name, self._cache[name]) 229 @return: deferred fired when data is actually saved
166 return self.storage.setIndPrivateBinary(self.namespace, name, self._cache[name], self.profile) 230 """
231 return self.storage.setPrivateValue(self.namespace, name, value, self.binary, self.profile)