Commit 1a72a60f authored by Julien Muchembled's avatar Julien Muchembled

storage: require backends to use @fallback implementation explicitly

... rather than logging when the backend does not override.
parent 042f5ac0
...@@ -74,7 +74,7 @@ def implements(obj, ignore=()): ...@@ -74,7 +74,7 @@ def implements(obj, ignore=()):
assert not wrong_signature, wrong_signature assert not wrong_signature, wrong_signature
return obj return obj
def _set_code(func): def _stub(func):
args, varargs, varkw, _ = inspect.getargspec(func) args, varargs, varkw, _ = inspect.getargspec(func)
if varargs: if varargs:
args.append("*" + varargs) args.append("*" + varargs)
...@@ -82,16 +82,25 @@ def _set_code(func): ...@@ -82,16 +82,25 @@ def _set_code(func):
args.append("**" + varkw) args.append("**" + varkw)
exec "def %s(%s): raise NotImplementedError\nf = %s" % ( exec "def %s(%s): raise NotImplementedError\nf = %s" % (
func.__name__, ",".join(args), func.__name__) func.__name__, ",".join(args), func.__name__)
func.func_code = f.func_code return f
def abstract(func): def abstract(func):
_set_code(func) f = _stub(func)
func.__abstract__ = 1 f.__abstract__ = 1
return func f.__defaults__ = func.__defaults__
f.__doc__ = func.__doc__
return f
def requires(*args): def requires(*args):
for func in args: for func in args:
_set_code(func) # Tolerate useless abstract decoration on required method (e.g. it
# simplifies the implementation of a fallback decorator), but remove
# marker since it does not need to be implemented if it's required
# by a method that is overridden.
try:
del func.__abstract__
except AttributeError:
func.__code__ = _stub(func).__code__
def decorator(func): def decorator(func):
func.__requires__ = args func.__requires__ = args
return func return func
......
...@@ -33,7 +33,7 @@ from ZODB.FileStorage import FileStorage ...@@ -33,7 +33,7 @@ from ZODB.FileStorage import FileStorage
from ..app import option_defaults from ..app import option_defaults
from . import buildDatabaseManager, DatabaseFailure from . import buildDatabaseManager, DatabaseFailure
from .manager import DatabaseManager from .manager import DatabaseManager, Fallback
from neo.lib import compress, logging, patch, util from neo.lib import compress, logging, patch, util
from neo.lib.interfaces import implements from neo.lib.interfaces import implements
from neo.lib.protocol import BackendNotImplemented, MAX_TID from neo.lib.protocol import BackendNotImplemented, MAX_TID
...@@ -692,6 +692,9 @@ class ImporterDatabaseManager(DatabaseManager): ...@@ -692,6 +692,9 @@ class ImporterDatabaseManager(DatabaseManager):
def _fetchObject(*_): def _fetchObject(*_):
raise AssertionError raise AssertionError
getLastObjectTID = Fallback.getLastObjectTID.__func__
_getDataTID = Fallback._getDataTID.__func__
def getObjectHistory(self, *args, **kw): def getObjectHistory(self, *args, **kw):
raise BackendNotImplemented(self.getObjectHistory) raise BackendNotImplemented(self.getObjectHistory)
......
...@@ -26,22 +26,9 @@ from . import DatabaseFailure ...@@ -26,22 +26,9 @@ from . import DatabaseFailure
READABLE = CellStates.UP_TO_DATE, CellStates.FEEDING READABLE = CellStates.UP_TO_DATE, CellStates.FEEDING
def lazymethod(func):
def getter(self):
cls = self.__class__
name = func.__name__
assert name not in cls.__dict__
setattr(cls, name, func(self))
return getattr(self, name)
return property(getter, doc=func.__doc__)
def fallback(func): def fallback(func):
def warn(self): setattr(Fallback, func.__name__, func)
logging.info("Fallback to generic/slow implementation of %s." return abstract(func)
" It should be overridden by backend storage (%s).",
func.__name__, self.__class__.__name__)
return func
return lazymethod(wraps(func)(warn))
def splitOIDField(tid, oids): def splitOIDField(tid, oids):
if len(oids) % 8: if len(oids) % 8:
...@@ -52,6 +39,9 @@ def splitOIDField(tid, oids): ...@@ -52,6 +39,9 @@ def splitOIDField(tid, oids):
class CreationUndone(Exception): class CreationUndone(Exception):
pass pass
class Fallback(object):
pass
class DatabaseManager(object): class DatabaseManager(object):
"""This class only describes an interface for database managers.""" """This class only describes an interface for database managers."""
...@@ -493,6 +483,7 @@ class DatabaseManager(object): ...@@ -493,6 +483,7 @@ class DatabaseManager(object):
None if data_serial is None else util.p64(data_serial)) None if data_serial is None else util.p64(data_serial))
@fallback @fallback
@requires(_getObject)
def _fetchObject(self, oid, tid): def _fetchObject(self, oid, tid):
"""Specialized version of _getObject, for replication""" """Specialized version of _getObject, for replication"""
r = self._getObject(oid, tid) r = self._getObject(oid, tid)
...@@ -738,6 +729,7 @@ class DatabaseManager(object): ...@@ -738,6 +729,7 @@ class DatabaseManager(object):
return self._pruneData(data_id_list) return self._pruneData(data_id_list)
@fallback @fallback
@requires(_getObject)
def _getDataTID(self, oid, tid=None, before_tid=None): def _getDataTID(self, oid, tid=None, before_tid=None):
""" """
Return a 2-tuple: Return a 2-tuple:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment