Commit 6ca0ab70 authored by Julien Muchembled's avatar Julien Muchembled

The implementation of some methods in storage backend is optional

If not implemented, this should not result in a fatal error that kills the
storage. Instead of that, a new error packet is sent so that the exception is
raised in the client.
parent de4c9e1d
...@@ -16,8 +16,9 @@ ...@@ -16,8 +16,9 @@
from . import logging from . import logging
from .protocol import ( from .protocol import (
NodeStates, Packets, Errors, BrokenNodeDisallowedError, NodeStates, Packets, Errors, BackendNotImplemented,
NotReadyError, PacketMalformedError, ProtocolError, UnexpectedPacketError) BrokenNodeDisallowedError, NotReadyError, PacketMalformedError,
ProtocolError, UnexpectedPacketError)
class EventHandler(object): class EventHandler(object):
...@@ -75,6 +76,11 @@ class EventHandler(object): ...@@ -75,6 +76,11 @@ class EventHandler(object):
message = str(message) message = str(message)
conn.answer(Errors.ProtocolError(message)) conn.answer(Errors.ProtocolError(message))
conn.abort() conn.abort()
except BackendNotImplemented, message:
m = message[0]
conn.answer(Errors.BackendNotImplemented(
"%s.%s does not implement %s"
% (m.im_class.__module__, m.im_class.__name__, m.__name__)))
except AssertionError: except AssertionError:
conn.close() conn.close()
raise raise
...@@ -183,3 +189,6 @@ class EventHandler(object): ...@@ -183,3 +189,6 @@ class EventHandler(object):
def ack(self, conn, message): def ack(self, conn, message):
logging.debug("no error message: %s", message) logging.debug("no error message: %s", message)
def backendNotImplemented(self, conn, message):
raise NotImplementedError(message)
...@@ -24,7 +24,7 @@ try: ...@@ -24,7 +24,7 @@ try:
except ImportError: except ImportError:
pass pass
PROTOCOL_VERSION = 1 PROTOCOL_VERSION = 2
# Size restrictions. # Size restrictions.
MIN_PACKET_SIZE = 10 MIN_PACKET_SIZE = 10
...@@ -78,6 +78,7 @@ def ErrorCodes(): ...@@ -78,6 +78,7 @@ def ErrorCodes():
ALREADY_PENDING ALREADY_PENDING
REPLICATION_ERROR REPLICATION_ERROR
CHECKING_ERROR CHECKING_ERROR
BACKEND_NOT_IMPLEMENTED
@Enum @Enum
def ClusterStates(): def ClusterStates():
...@@ -185,23 +186,21 @@ uuid_str = (lambda ns: lambda uuid: ...@@ -185,23 +186,21 @@ uuid_str = (lambda ns: lambda uuid:
class ProtocolError(Exception): class ProtocolError(Exception):
""" Base class for protocol errors, close the connection """ """ Base class for protocol errors, close the connection """
pass
class PacketMalformedError(ProtocolError): class PacketMalformedError(ProtocolError):
""" Close the connection and set the node as broken""" """ Close the connection and set the node as broken"""
pass
class UnexpectedPacketError(ProtocolError): class UnexpectedPacketError(ProtocolError):
""" Close the connection and set the node as broken""" """ Close the connection and set the node as broken"""
pass
class NotReadyError(ProtocolError): class NotReadyError(ProtocolError):
""" Just close the connection """ """ Just close the connection """
pass
class BrokenNodeDisallowedError(ProtocolError): class BrokenNodeDisallowedError(ProtocolError):
""" Just close the connection """ """ Just close the connection """
pass
class BackendNotImplemented(Exception):
""" Method not implemented by backend storage """
class Packet(object): class Packet(object):
""" """
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
from collections import defaultdict from collections import defaultdict
from functools import wraps from functools import wraps
from neo.lib import logging, util from neo.lib import logging, util
from neo.lib.protocol import ZERO_TID from neo.lib.protocol import ZERO_TID, BackendNotImplemented
def lazymethod(func): def lazymethod(func):
def getter(self): def getter(self):
...@@ -500,7 +500,7 @@ class DatabaseManager(object): ...@@ -500,7 +500,7 @@ class DatabaseManager(object):
The length specifies the maximum size of such a list. Result starts The length specifies the maximum size of such a list. Result starts
with latest serial, and the list must be sorted in descending order. with latest serial, and the list must be sorted in descending order.
If there is no such object ID in a database, return None.""" If there is no such object ID in a database, return None."""
raise NotImplementedError raise BackendNotImplemented(self.getObjectHistory)
def getReplicationObjectList(self, min_tid, max_tid, length, partition, def getReplicationObjectList(self, min_tid, max_tid, length, partition,
min_oid): min_oid):
...@@ -513,7 +513,7 @@ class DatabaseManager(object): ...@@ -513,7 +513,7 @@ class DatabaseManager(object):
"""Return a list of TIDs in ascending order from an offset, """Return a list of TIDs in ascending order from an offset,
at most the specified length. The list of partitions are passed at most the specified length. The list of partitions are passed
to filter out non-applicable TIDs.""" to filter out non-applicable TIDs."""
raise NotImplementedError raise BackendNotImplemented(self.getTIDList)
def getReplicationTIDList(self, min_tid, max_tid, length, partition): def getReplicationTIDList(self, min_tid, max_tid, length, partition):
"""Return a list of TIDs in ascending order from an initial tid value, """Return a list of TIDs in ascending order from an initial tid value,
......
...@@ -93,6 +93,8 @@ class ImporterTests(NEOThreadedTest): ...@@ -93,6 +93,8 @@ class ImporterTests(NEOThreadedTest):
cluster.start() cluster.start()
t, c = cluster.getTransaction() t, c = cluster.getTransaction()
r = c.root()["neo"] r = c.root()["neo"]
self.assertRaisesRegexp(NotImplementedError, " getObjectHistory$",
c.db().history, r._p_oid)
i = r.walk() i = r.walk()
next(islice(i, 9, None)) next(islice(i, 9, None))
dm.doOperation(cluster.storage) # resume dm.doOperation(cluster.storage) # resume
......
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