Created
October 10, 2015 15:28
-
-
Save fjkz/6239760499a791baba34 to your computer and use it in GitHub Desktop.
A simple Paxos implementation for study.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
A simple Paxos implementation for study. | |
""" | |
from collections import Counter | |
class Proposer: | |
def __init__(self, acceptors): | |
self.acceptors = acceptors | |
self.number = 0 | |
self.value = 'proposal value' | |
self.preparing_acceptors = [] | |
def send_prepare_requests(self): | |
print('Start sending prepare requests.') | |
self.preparing_acceptors = [] | |
highest_res_num = -1 | |
for acceptor in acceptors: | |
print(' Send a prepare request to ' + str(acceptor) + | |
' with no = ' + str(self.number) + '.') | |
try: | |
responce = acceptor.prepare(self.number) | |
except IOError: | |
print(' Failed to send a prepare request to ' + str(acceptor) + '.') | |
continue | |
self.preparing_acceptors.append(acceptor) | |
res_number = responce[0] | |
res_value = responce[1] | |
if res_number > highest_res_num: | |
highest_res_num = number | |
# Remember the highest-numbered proposal among the responces. | |
self.value = value | |
num_acceptors = len(self.acceptors) | |
num_preparing = len(self.preparing_acceptors) | |
print(str(num_preparing) + ' / ' + str(num_acceptors) + ' are preparing.') | |
if (num_preparing < num_acceptors // 2 + 1): | |
print('Acceptors that responded to a prepare request are not majority.') | |
return | |
print('Finish sending prepare requests.') | |
def send_accept_requests(self): | |
print('Start to send accept requests.') | |
for acceptor in self.preparing_acceptors: | |
print(' Send a accept request to ' + str(acceptor) + | |
' with no = ' + str(self.number) + | |
', value = "' + str(self.value) + '".') | |
try: | |
acceptor.accept(self.number, self.value) | |
except IOError: | |
print(' Failed to send a accept request to ' + str(acceptor)) | |
print('Finish sending accept requests.') | |
class Acceptor: | |
def __init__(self, name, learners): | |
self.name = name | |
self.learners = learners | |
self.prepared_number = -1 | |
self.accepted_number = -1 | |
self.accepted_value = None | |
def __str__(self): | |
return self.name | |
def prepare(self, proposal_number): | |
if proposal_number <= self.prepared_number: | |
return None | |
self.prepared_number = proposal_number | |
# If not accept any proposal yet, return (-1, None) | |
return (self.accepted_number, self.accepted_value) | |
def accept(self, proposal_number, proposal_value): | |
if proposal_number < self.prepared_number: | |
return | |
self.accepted_number = proposal_number | |
self.accepted_value = proposal_value | |
for learner in self.learners: | |
learner.learn_accepted_value( | |
self.name, proposal_number, proposal_value) | |
class Learner: | |
def __init__(self, num_acceptors): | |
self.num_acceptors = num_acceptors | |
self.accepting_acceptors = [] | |
self.accepted_value = [] | |
def learn_accepted_value( | |
self, name, proposal_number, proposal_value): | |
print(' ' + str(name) + ' accepted "' + | |
str(proposal_value) + '".') | |
self.accepting_acceptors.append(name) | |
self.accepted_value.append(proposal_value) | |
def get_chosen_value(self): | |
most_common, num_most_common = \ | |
Counter(self.accepted_value).most_common(1)[0] | |
if num_most_common < num_acceptors // 2 + 1: | |
print('The mostly accepted value is "' + str(most_common) + '", but not majority.') | |
return None | |
print('The chosen value is "' + str(most_common) + '".') | |
return most_common | |
if __name__ == '__main__': | |
num_acceptors = 2 | |
learner = Learner(2) | |
acceptors = [] | |
for i in range(num_acceptors): | |
name = 'a' + str(i) | |
learners = [learner] | |
acceptor = Acceptor(name, learners) | |
acceptors.append(acceptor) | |
proposer = Proposer(acceptors) | |
proposer.send_prepare_requests() | |
proposer.send_accept_requests() | |
learner.get_chosen_value() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
hey Brother,
can you help me how to use this code