Mercurial > libervia-backend
diff 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 |
line wrap: on
line diff
--- a/src/memory/persistent.py Sun Mar 12 19:32:59 2017 +0100 +++ b/src/memory/persistent.py Sun Mar 12 19:33:17 2017 +0100 @@ -28,30 +28,38 @@ class PersistentDict(object): r"""A dictionary which save persistently each value assigned + /!\ be careful, each assignment means a database write /!\ Memory must be initialised before loading/setting value with instances of this class""" storage = None + binary = False def __init__(self, namespace, profile=None): - """@param namespace: unique namespace for this dictionary - @param profile: profile which *MUST* exists, or None for general values""" + """ + + @param namespace: unique namespace for this dictionary + @param profile(unicode, None): profile which *MUST* exists, or None for general values + """ if not self.storage: log.error(_("PersistentDict can't be used before memory initialisation")) raise MemoryNotInitializedError - self._cache = {} + self._cache = None self.namespace = namespace self.profile = profile + def _setCache(self, data): + self._cache = data + def load(self): """Load persistent data from storage. + need to be called before any other operation @return: defers the PersistentDict instance itself """ - if not self.profile: - d = self.storage.loadGenPrivates(self._cache, self.namespace) - else: - d = self.storage.loadIndPrivates(self._cache, self.namespace, self.profile) - return d.addCallback(lambda dummy: self) + d = self.storage.getPrivates(self.namespace, binary=self.binary, profile=self.profile) + d.addCallback(self._setCache) + d.addCallback(lambda dummy: self) + return d def iteritems(self): return self._cache.iteritems() @@ -102,17 +110,11 @@ return self._cache.__getitem__(key) def __setitem__(self, key, value): - if not self.profile: - self.storage.setGenPrivate(self.namespace, key, value) - else: - self.storage.setIndPrivate(self.namespace, key, value, self.profile) + self.storage.setPrivateValue(self.namespace, key, value, self.binary, self.profile) return self._cache.__setitem__(key, value) def __delitem__(self, key): - if not self.profile: - self.storage.delGenPrivate(self.namespace, key) - else: - self.storage.delIndPrivate(self.namespace, key, self.profile) + self.storage.detPrivateValue(self.namepace, key, self.binary, self.profile) return self._cache.__delitem__(key) def get(self, key, default=None): @@ -127,40 +129,103 @@ def force(self, name): """Force saving of an attribute to storage - @return: deferred fired when data is actually saved""" - if not self.profile: - return self.storage.setGenPrivate(self.namespace, name, self._cache[name]) - return self.storage.setIndPrivate(self.namespace, name, self._cache[name], self.profile) + + @return: deferred fired when data is actually saved + """ + return self.storage.setPrivateValue(self.namespace, name, self._cache[name], self.binary, self.profile) class PersistentBinaryDict(PersistentDict): """Persistent dict where value can be any python data (instead of string only)""" + binary = True + + +class LazyPersistentBinaryDict(PersistentBinaryDict): + ur"""PersistentBinaryDict which get key/value when needed + + This Persistent need more database access, it is suitable for largest data, + to save memory. + /!\ most of methods return a Deferred + """ + # TODO: missing methods should be implemented using database access + # TODO: a cache would be useful (which is deleted after a timeout) def load(self): - """load persistent data from storage - """ - if not self.profile: - return self.storage.loadGenPrivatesBinary(self._cache, self.namespace) - else: - return self.storage.loadIndPrivatesBinary(self._cache, self.namespace, self.profile) + # we show a warning as calling load on LazyPersistentBinaryDict sounds like a code mistake + log.warning(_(u"Calling load on LazyPersistentBinaryDict while it's not needed")) + + def iteritems(self): + raise NotImplementedError + + def items(self): + return self.storage.getPrivates(self.namespace, binary=self.binary, profile=self.profile) + + def __repr__(self): + raise NotImplementedError + + def __str__(self): + return "LazyPersistentBinaryDict (namespace: {})".format(self.namespace) + + def __lt__(self, other): + raise NotImplementedError + + def __le__(self, other): + raise NotImplementedError + + def __eq__(self, other): + raise NotImplementedError + + def __ne__(self, other): + raise NotImplementedError + + def __gt__(self, other): + raise NotImplementedError + + def __ge__(self, other): + raise NotImplementedError + + def __cmp__(self, other): + raise NotImplementedError + + def __hash__(self): + return hash(unicode(self.__class__) + self.namespace + (self.profile or u'')) + + def __nonzero__(self): + raise NotImplementedError + + def __contains__(self, key): + raise NotImplementedError + + def __iter__(self): + raise NotImplementedError + + def __getitem__(self, key): + """get the value as a Deferred""" + return self.storage.getPrivates(self.namespace, keys=[key], binary=self.binary, profile=self.profile) def __setitem__(self, key, value): - if not self.profile: - self.storage.setGenPrivateBinary(self.namespace, key, value) - else: - self.storage.setIndPrivateBinary(self.namespace, key, value, self.profile) - return self._cache.__setitem__(key, value) + self.storage.setPrivateValue(self.namespace, key, value, self.binary, self.profile) def __delitem__(self, key): - if not self.profile: - self.storage.delGenPrivateBinary(self.namespace, key) - else: - self.storage.delIndPrivateBinary(self.namespace, key, self.profile) - return self._cache.__delitem__(key) + self.storage.detPrivateValue(self.namepace, key, self.binary, self.profile) + + def _valueOrDefault(self, value, default): + if value is None: + return default + return value - def force(self, name): + def get(self, key, default=None): + d = self.__getitem__(key) + d.addCallback(self._valueOrDefault) + return d + + def setdefault(self, key, default): + raise NotImplementedError + + def force(self, name, value): """Force saving of an attribute to storage - @return: deferred fired when data is actually saved""" - if not self.profile: - return self.storage.setGenPrivateBinary(self.namespace, name, self._cache[name]) - return self.storage.setIndPrivateBinary(self.namespace, name, self._cache[name], self.profile) + + @param value(object): value is needed for LazyPersistentBinaryDict + @return: deferred fired when data is actually saved + """ + return self.storage.setPrivateValue(self.namespace, name, value, self.binary, self.profile)