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):
addr = self.primary_master_node.getAddress()
for conn in self.em.getServerList():
conn.close()
for conn in self.em.getClientList():
if conn.getAddress() != addr:
conn.close()
connected_to_master = False
primary_handler = secondary.PrimaryHandler(self)
# But if there is no such connection, something wrong
# happened.
for conn in self.em.getClientList():
if conn.getAddress() == addr:
# primary master elected and connected
break
else:
raise ElectionFailure('No connection remains to the primary')
connected_to_master = True
conn.setHandler(primary_handler)
else:
conn.close()
if not connected_to_master:
ClientConnection(self.em, primary_handler, addr=addr,
connector_handler=self.connector_handler)
def _electionFailed(self, m):
......@@ -628,12 +630,6 @@ class Application(object):
# otherwise, wait for the primary announcement
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
handler = identification.IdentificationHandler(self)
self.listening_conn.setHandler(handler)
......
......@@ -193,9 +193,8 @@ class ClientElectionHandler(ElectionHandler):
app.primary_master_node = primary_node
# Stop waiting for connections than primary master's to
# complete to exit election phase ASAP.
primary_server = primary_node.getAddress()
app.unconnected_master_node_set = set([primary_server])
app.negotiating_master_node_set = set([primary_server])
app.unconnected_master_node_set.clear()
app.negotiating_master_node_set.clear()
# Request a node identification.
conn.ask(Packets.RequestIdentification(
......@@ -270,5 +269,7 @@ class ServerElectionHandler(ElectionHandler):
node = app.nm.getByUUID(uuid)
app.primary = False
app.primary_master_node = node
app.unconnected_master_node_set.clear()
app.negotiating_master_node_set.clear()
logging.info('%s is the primary', node)
......@@ -20,7 +20,7 @@ from neo import logging
from neo.master.handlers import MasterHandler
from neo.exception import ElectionFailure, PrimaryFailure
from neo import protocol
from neo.protocol import NodeTypes
from neo.protocol import NodeTypes, Packets
class SecondaryMasterHandler(MasterHandler):
""" Handler used by primary to handle secondary masters"""
......@@ -58,6 +58,18 @@ class PrimaryHandler(MasterHandler):
self.app.primary_master_node.setDown()
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):
raise ElectionFailure, 'reelection requested'
......@@ -98,7 +110,15 @@ class PrimaryHandler(MasterHandler):
node.setUUID(uuid)
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):
pass
......@@ -194,8 +194,8 @@ class MasterClientElectionTests(NeoTestBase):
master_list = self._getMasterList()
self.election.answerPrimary(conn, node.getUUID(), master_list)
addr = conn.getAddress()
self.assertTrue(addr in self.app.unconnected_master_node_set)
self.assertTrue(addr in self.app.negotiating_master_node_set)
self.assertEqual(len(self.app.unconnected_master_node_set), 0)
self.assertEqual(len(self.app.negotiating_master_node_set), 0)
self.assertFalse(self.app.primary)
self.assertEqual(self.app.primary_master_node, node)
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