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): ...@@ -77,6 +77,7 @@ class HandlerSwitcher(object):
self._connection = connection self._connection = connection
# pending handlers and related requests # pending handlers and related requests
self._pending = [[{}, handler]] self._pending = [[{}, handler]]
self._is_handling = False
def clear(self): def clear(self):
handler = self._pending[0][1] handler = self._pending[0][1]
...@@ -92,6 +93,12 @@ class HandlerSwitcher(object): ...@@ -92,6 +93,12 @@ class HandlerSwitcher(object):
def emit(self, request, timeout): def emit(self, request, timeout):
# register the request in the current handler # register the request in the current handler
_pending = self._pending _pending = self._pending
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] assert len(_pending) == 1 or _pending[0][0]
(request_dict, _) = _pending[-1] (request_dict, _) = _pending[-1]
msg_id = request.getId() msg_id = request.getId()
...@@ -112,8 +119,16 @@ class HandlerSwitcher(object): ...@@ -112,8 +119,16 @@ class HandlerSwitcher(object):
result = None result = None
return result return result
@profiler_decorator
def handle(self, packet): 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] assert len(self._pending) == 1 or self._pending[0][0]
PACKET_LOGGER.dispatch(self._connection, packet, 'from') PACKET_LOGGER.dispatch(self._connection, packet, 'from')
msg_id = packet.getId() msg_id = packet.getId()
......
...@@ -851,10 +851,30 @@ class HandlerSwitcherTests(NeoTestBase): ...@@ -851,10 +851,30 @@ class HandlerSwitcherTests(NeoTestBase):
self.assertFalse(self._handlers.isPending()) self.assertFalse(self._handlers.isPending())
def testEmit(self): def testEmit(self):
# First case, emit is called outside of a handler
self.assertFalse(self._handlers.isPending()) self.assertFalse(self._handlers.isPending())
request = self._makeRequest(1) request = self._makeRequest(1)
self._handlers.emit(request, 0) self._handlers.emit(request, 0)
self.assertTrue(self._handlers.isPending()) 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): def testHandleNotification(self):
# handle with current handler # 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