Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

INDY-1112: change primeries election procedure for backup instances. #539

Merged
merged 10 commits into from
Feb 28, 2018

Conversation

sergey-shilov
Copy link
Contributor

Now primaries for backup instances are choosen in round-robin
manner always starting from primary. If the next node is a primary
for some instance then this node is skipped. So the first non-primary
node is choosen as primary for current instance. Such approach allows
to avoid election of instances of the same node as a primeries for
different instances.
The election procedure of the primary for master instance is not changed.

Signed-off-by: Sergey Shilov [email protected]

@ghost
Copy link

ghost commented Feb 19, 2018

Could one of the committers please verify this patch?

Now primaries for backup instances are choosen in round-robin
manner always starting from primary. If the next node is a primary
for some instance then this node is skipped. So the first non-primary
node is choosen as primary for current instance. Such approach allows
to avoid election of instances of the same node as a primeries for
different instances.
The election procedure of the primary for master instance is not changed.

Signed-off-by: Sergey Shilov <[email protected]>
logger.trace("{} selected {} as next primary node for instId {}, "
"viewNo {} with rank {}, nodeReg {}".format(
self, name, instance_id, self.viewNo, rank, nodeReg))
assert name, "{} failed to get next primary node name".format(self)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we "assert name" before logging that primary was selected?
What should we do if name is None?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course "assert name" should be before logging.
If name is None then Apocalypse has come. It can not be None by design, otherwise implementation is incorrect.

'''
if instance_id == 0:
primary_rank = self.poolManager.get_rank_by_name(
replica.primaryName.split(":", 1)[0], nodeReg)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't use name variable here instead of replica.primaryName.split(":", 1)[0]?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because replica.primaryName in fact is not just node name, it has a form "node_name:instance_id". So it would be nice to rename replica.primaryName to replica.primaryInstanceName, I'll check how wide re-factoring it will cause.

def next_primary_replica_name_for_backup(self, instance_id, master_primary_rank,
primaries, nodeReg=None):
"""
Returns name of the next node which is supposed to be a new Primary
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please correct the description since it's not a real round robin, but it takes into account the other primaries.
Please mention that we return two values, not just name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... On my opinion it is pure round robin, the only thing is that we may skip some nodes, but it is round robin anyway.
As for primary for master replica - this is not round robin, I think. There is a formula that is not changed in scope of these changes:
(view_no + instance_id) % total_nodes
I really don't see round robin here.
As for returned two values - done.


return name

def next_primary_replica_name_for_master(self, nodeReg=None):
"""
Returns name of the next node which is supposed to be a new Primary
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please mention that we return two values, not just name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


return name

def next_primary_replica_name_for_master(self, nodeReg=None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a unit test for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

name = self.next_primary_node_name_for_master(nodeReg)
return name, Replica.generateName(nodeName=name, instId=0)

def next_primary_replica_name_for_backup(self, instance_id, master_primary_rank,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a unit test for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -2354,15 +2354,42 @@ def lost_master_primary(self):
self._schedule_view_change()

def select_primaries(self, nodeReg: Dict[str, HA]=None):
primaries = set()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add an integration test for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Build a set of names of primaries, it is needed to avoid
duplicates of primary nodes for different replicas.
'''
for instance_id, replica in enumerate(self.replicas):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to keep track of 'old' primaries just to avoid selecting the same primaries as was before?
Please add a test for this!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -2354,15 +2354,42 @@ def lost_master_primary(self):
self._schedule_view_change()

def select_primaries(self, nodeReg: Dict[str, HA]=None):
primaries = set()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move all this logic to primary_selector?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have not information about primaries on primary_selector level.


return name

def next_primary_node_name_for_backup(self, instance_id, nodeReg=None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this method at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it is already deleted.

@@ -54,14 +54,56 @@ def next_primary_node_name(self, instance_id, nodeReg=None):

return name

def next_primary_replica_name(self, instance_id, nodeReg=None):
def next_primary_node_name_for_master(self, nodeReg=None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this method must be private (with _ prefix).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@sergey-shilov
Copy link
Contributor Author

Test this please.

Sergey Shilov added 2 commits February 20, 2018 19:01
assert primariesIdxs[1] == 1

master_node = txnPoolMasterNodes[0]
client, wallet = stewardAndWalletForMasterNode
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use SDK here?

yield nodes


def test_primaties_selection(txnPoolNodeSetWithElector):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a typo in the test name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

yield nodes


def test_primaties_selection(txnPoolNodeSetWithElector):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please split the test into a multiple of small tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

primaries = set()
view_no_bak = node.elector.viewNo
node.elector.viewNo = view_no
for instance_id in range(0, node.replicas.num_replicas):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we write it in a more simple way without a loop and if-else conditions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-factored.

Sergey Shilov added 4 commits February 22, 2018 13:58
Signed-off-by: Sergey Shilov <[email protected]>
…oolManager.

Now a node adds itself to nodeReg during catch-up of pool ledger.

Signed-off-by: Sergey Shilov <[email protected]>
Signed-off-by: Sergey Shilov <[email protected]>
@ashcherbakov
Copy link
Contributor

test this please

@@ -272,6 +272,18 @@ def nodeHaChanged(self, txn):
# TODO: Check if new HA is same as old HA and only update if
# new HA is different.
if nodeName == self.name:
# Update itself in node registry if needed
(ip, port) = self.node.nodeReg[nodeName]
if ip != txn[DATA][NODE_IP] or port != txn[DATA][NODE_PORT]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if txn conatins IP only (or PORT only)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bad things will happen in this case... Additional checks should be added.

@sergey-shilov
Copy link
Contributor Author

Test this please.

@ashcherbakov ashcherbakov merged commit f4a5fa8 into hyperledger:master Feb 28, 2018
lampkin-diet pushed a commit to lampkin-diet/indy-plenum that referenced this pull request Apr 9, 2018
…yperledger#539)

* INDY-1112: change primeries election procedure for backup instances.

Now primaries for backup instances are choosen in round-robin
manner always starting from primary. If the next node is a primary
for some instance then this node is skipped. So the first non-primary
node is choosen as primary for current instance. Such approach allows
to avoid election of instances of the same node as a primeries for
different instances.
The election procedure of the primary for master instance is not changed.

Signed-off-by: Sergey Shilov <[email protected]>

* Add some stylistical fixes, add comments.

Signed-off-by: Sergey Shilov <[email protected]>

* Add test for primary demotion and promotion.

Signed-off-by: Sergey Shilov <[email protected]>

* Add test for primaries selection routines.

Signed-off-by: Sergey Shilov <[email protected]>

* Re-factor primary selector tests.

Signed-off-by: Sergey Shilov <[email protected]>

* Remove adding of node itself to nodeReg during initialisation of txnPoolManager.

Now a node adds itself to nodeReg during catch-up of pool ledger.

Signed-off-by: Sergey Shilov <[email protected]>

* Fix test.

Signed-off-by: Sergey Shilov <[email protected]>

* Update node's HA in node registry on pool ledger catch-up reply.

Signed-off-by: Sergey Shilov <[email protected]>

* Add separate checks for IP/port to be updated for HA and cliHA.

Signed-off-by: Sergey Shilov <[email protected]>
lampkin-diet pushed a commit to lampkin-diet/indy-plenum that referenced this pull request Apr 10, 2018
…yperledger#539)

* INDY-1112: change primeries election procedure for backup instances.

Now primaries for backup instances are choosen in round-robin
manner always starting from primary. If the next node is a primary
for some instance then this node is skipped. So the first non-primary
node is choosen as primary for current instance. Such approach allows
to avoid election of instances of the same node as a primeries for
different instances.
The election procedure of the primary for master instance is not changed.

Signed-off-by: Sergey Shilov <[email protected]>

* Add some stylistical fixes, add comments.

Signed-off-by: Sergey Shilov <[email protected]>

* Add test for primary demotion and promotion.

Signed-off-by: Sergey Shilov <[email protected]>

* Add test for primaries selection routines.

Signed-off-by: Sergey Shilov <[email protected]>

* Re-factor primary selector tests.

Signed-off-by: Sergey Shilov <[email protected]>

* Remove adding of node itself to nodeReg during initialisation of txnPoolManager.

Now a node adds itself to nodeReg during catch-up of pool ledger.

Signed-off-by: Sergey Shilov <[email protected]>

* Fix test.

Signed-off-by: Sergey Shilov <[email protected]>

* Update node's HA in node registry on pool ledger catch-up reply.

Signed-off-by: Sergey Shilov <[email protected]>

* Add separate checks for IP/port to be updated for HA and cliHA.

Signed-off-by: Sergey Shilov <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants