Commit 81ee387a authored by Vincent Pelletier's avatar Vincent Pelletier

Exit election as soon as primary master is known.

It has no meaning to stay in election state when the primary master is
known. Also, it causes problems as the elected primary master will soon
start sending packets we don't expect while election is running.

handler/election.py:
- Receiving announcePrimary is enough to exit election immediately, so
  reach election end condition (both sets must be empty)
- Receiving answerPrimary with a known primary is enough to exit election
  immediately (don't attempt to connect to to primary master).
app.py:
- Apply PrimaryHandler while iterating over connections when the primary
  master connection is found, rather than once all other connections are
  closed.
- If no primary master connection was found, start establishing one.
handlers/secondary.py:
- Handle connectionCompleted event as we might only reach primary master
  once with this handler if connection was not established during election.
- Likewise, handle connectionFailed event, and treat it as a primary
  failure.
- Stop ignoring answerPrimary packets, instead check that advertised
  primary master is the expected one and request node identification.

git-svn-id: https://svn.erp5.org/repos/neo/trunk@1583 71dcc9de-d417-0410-9af5-da40c76e7ee4
parent 7ad02d86
...@@ -238,18 +238,20 @@ class Application(object): ...@@ -238,18 +238,20 @@ class Application(object):
addr = self.primary_master_node.getAddress() addr = self.primary_master_node.getAddress()
for conn in self.em.getServerList(): for conn in self.em.getServerList():
conn.close() conn.close()
for conn in self.em.getClientList(): connected_to_master = False
if conn.getAddress() != addr:
conn.close() primary_handler = secondary.PrimaryHandler(self)
# But if there is no such connection, something wrong
# happened.
for conn in self.em.getClientList(): for conn in self.em.getClientList():
if conn.getAddress() == addr: if conn.getAddress() == addr:
# primary master elected and connected connected_to_master = True
break conn.setHandler(primary_handler)
else: else:
raise ElectionFailure('No connection remains to the primary') conn.close()
if not connected_to_master:
ClientConnection(self.em, primary_handler, addr=addr,
connector_handler=self.connector_handler)
def _electionFailed(self, m): def _electionFailed(self, m):
...@@ -628,12 +630,6 @@ class Application(object): ...@@ -628,12 +630,6 @@ class Application(object):
# otherwise, wait for the primary announcement # otherwise, wait for the primary announcement
self._waitForPrimaryAnnouncement() self._waitForPrimaryAnnouncement()
# apply the new handler to the primary connection
client_list = [x for x in self.em.getClientList() if x.getUUID() ==
self.primary_master_node.getUUID()]
assert len(client_list) == 1
client_list[0].setHandler(secondary.PrimaryHandler(self))
# and another for the future incoming connections # and another for the future incoming connections
handler = identification.IdentificationHandler(self) handler = identification.IdentificationHandler(self)
self.listening_conn.setHandler(handler) self.listening_conn.setHandler(handler)
......
...@@ -193,9 +193,8 @@ class ClientElectionHandler(ElectionHandler): ...@@ -193,9 +193,8 @@ class ClientElectionHandler(ElectionHandler):
app.primary_master_node = primary_node app.primary_master_node = primary_node
# Stop waiting for connections than primary master's to # Stop waiting for connections than primary master's to
# complete to exit election phase ASAP. # complete to exit election phase ASAP.
primary_server = primary_node.getAddress() app.unconnected_master_node_set.clear()
app.unconnected_master_node_set = set([primary_server]) app.negotiating_master_node_set.clear()
app.negotiating_master_node_set = set([primary_server])
# Request a node identification. # Request a node identification.
conn.ask(Packets.RequestIdentification( conn.ask(Packets.RequestIdentification(
...@@ -270,5 +269,7 @@ class ServerElectionHandler(ElectionHandler): ...@@ -270,5 +269,7 @@ class ServerElectionHandler(ElectionHandler):
node = app.nm.getByUUID(uuid) node = app.nm.getByUUID(uuid)
app.primary = False app.primary = False
app.primary_master_node = node app.primary_master_node = node
app.unconnected_master_node_set.clear()
app.negotiating_master_node_set.clear()
logging.info('%s is the primary', node) logging.info('%s is the primary', node)
...@@ -20,7 +20,7 @@ from neo import logging ...@@ -20,7 +20,7 @@ from neo import logging
from neo.master.handlers import MasterHandler from neo.master.handlers import MasterHandler
from neo.exception import ElectionFailure, PrimaryFailure from neo.exception import ElectionFailure, PrimaryFailure
from neo import protocol from neo import protocol
from neo.protocol import NodeTypes from neo.protocol import NodeTypes, Packets
class SecondaryMasterHandler(MasterHandler): class SecondaryMasterHandler(MasterHandler):
""" Handler used by primary to handle secondary masters""" """ Handler used by primary to handle secondary masters"""
...@@ -58,6 +58,18 @@ class PrimaryHandler(MasterHandler): ...@@ -58,6 +58,18 @@ class PrimaryHandler(MasterHandler):
self.app.primary_master_node.setDown() self.app.primary_master_node.setDown()
raise PrimaryFailure, 'primary master is dead' raise PrimaryFailure, 'primary master is dead'
def connectionFailed(self, conn):
self.app.primary_master_node.setDown()
raise PrimaryFailure, 'primary master is dead'
def connectionCompleted(self, conn):
addr = conn.getAddress()
node = self.app.nm.getByAddress(addr)
# connection successfull, set it as running
node.setRunning()
conn.ask(Packets.AskPrimary())
MasterHandler.connectionCompleted(self, conn)
def reelectPrimary(self, conn): def reelectPrimary(self, conn):
raise ElectionFailure, 'reelection requested' raise ElectionFailure, 'reelection requested'
...@@ -98,7 +110,15 @@ class PrimaryHandler(MasterHandler): ...@@ -98,7 +110,15 @@ class PrimaryHandler(MasterHandler):
node.setUUID(uuid) node.setUUID(uuid)
def answerPrimary(self, conn, primary_uuid, known_master_list): def answerPrimary(self, conn, primary_uuid, known_master_list):
pass app = self.app
if primary_uuid != app.primary_master_node.getUUID():
raise PrimaryFailure, 'unexpected primary uuid'
conn.ask(Packets.RequestIdentification(
NodeTypes.MASTER,
app.uuid,
app.server,
app.name
))
def notifyClusterInformation(self, conn, state): def notifyClusterInformation(self, conn, state):
pass pass
...@@ -194,8 +194,8 @@ class MasterClientElectionTests(NeoTestBase): ...@@ -194,8 +194,8 @@ class MasterClientElectionTests(NeoTestBase):
master_list = self._getMasterList() master_list = self._getMasterList()
self.election.answerPrimary(conn, node.getUUID(), master_list) self.election.answerPrimary(conn, node.getUUID(), master_list)
addr = conn.getAddress() addr = conn.getAddress()
self.assertTrue(addr in self.app.unconnected_master_node_set) self.assertEqual(len(self.app.unconnected_master_node_set), 0)
self.assertTrue(addr in self.app.negotiating_master_node_set) self.assertEqual(len(self.app.negotiating_master_node_set), 0)
self.assertFalse(self.app.primary) self.assertFalse(self.app.primary)
self.assertEqual(self.app.primary_master_node, node) self.assertEqual(self.app.primary_master_node, node)
self.checkRequestIdentification(conn) self.checkRequestIdentification(conn)
......
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