Commit d7748d3c authored by Vincent Pelletier's avatar Vincent Pelletier

Allow a handler to send requests.

When a handler sends a request, always queue the response for handling
within the same handler, possibly delaying further a pending handler
switch.
This is for example required to properly complete identification between
master nodes, as the connecting master node might exit election phase
before receiving peer's AnswerPrimary when peer happens to be the primary.

git-svn-id: https://svn.erp5.org/repos/neo/trunk@2035 71dcc9de-d417-0410-9af5-da40c76e7ee4
parent f26b5b9c
......@@ -77,6 +77,7 @@ class HandlerSwitcher(object):
self._connection = connection
# pending handlers and related requests
self._pending = [[{}, handler]]
self._is_handling = False
def clear(self):
handler = self._pending[0][1]
......@@ -92,8 +93,14 @@ class HandlerSwitcher(object):
def emit(self, request, timeout):
# register the request in the current handler
_pending = self._pending
assert len(_pending) == 1 or _pending[0][0]
(request_dict, _) = _pending[-1]
if self._is_handling:
# If this is called while handling a packet, the response is to
# be excpected for the current handler...
(request_dict, _) = _pending[0]
else:
# ...otherwise, queue for for the latest handler
assert len(_pending) == 1 or _pending[0][0]
(request_dict, _) = _pending[-1]
msg_id = request.getId()
answer_class = request.getAnswerClass()
assert answer_class is not None, "Not a request"
......@@ -112,8 +119,16 @@ class HandlerSwitcher(object):
result = None
return result
@profiler_decorator
def handle(self, packet):
assert not self._is_handling
self._is_handling = True
try:
self._handle(packet)
finally:
self._is_handling = False
@profiler_decorator
def _handle(self, packet):
assert len(self._pending) == 1 or self._pending[0][0]
PACKET_LOGGER.dispatch(self._connection, packet, 'from')
msg_id = packet.getId()
......
......@@ -851,10 +851,30 @@ class HandlerSwitcherTests(NeoTestBase):
self.assertFalse(self._handlers.isPending())
def testEmit(self):
# First case, emit is called outside of a handler
self.assertFalse(self._handlers.isPending())
request = self._makeRequest(1)
self._handlers.emit(request, 0)
self.assertTrue(self._handlers.isPending())
# Second case, emit is called from inside a handler with a pending
# handler change.
new_handler = self._makeHandler()
self._handlers.setHandler(new_handler)
self._checkCurrentHandler(self._handler)
call_tracker = []
def packetReceived(conn, packet):
self._handlers.emit(self._makeRequest(2), 0)
call_tracker.append(True)
self._handler.packetReceived = packetReceived
self._handlers.handle(self._makeAnswer(1))
self.assertEqual(call_tracker, [True])
# Effective handler must not have changed (new request is blocking
# it)
self._checkCurrentHandler(self._handler)
# Handling the next response will cause the handler to change
delattr(self._handler, 'packetReceived')
self._handlers.handle(self._makeAnswer(2))
self._checkCurrentHandler(new_handler)
def testHandleNotification(self):
# handle with current handler
......
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