1
1
# Copyright (C) 2011 Johan Rydberg
2
- # Copyright (C) 2010 Bob Potter
3
2
#
4
3
# Permission is hereby granted, free of charge, to any person
5
4
# obtaining a copy of this software and associated documentation files
@@ -46,31 +45,31 @@ class LeaderElectionMixin:
46
45
VOTE_KEY = 'leader:vote'
47
46
LEADER_KEY = 'leader:leader'
48
47
49
- def __init__ (self , clock ):
48
+ def __init__ (self , clock , vote_delay = 5 ):
50
49
self .clock = clock
51
50
self ._election_timeout = None
52
51
self ._gossiper = None
52
+ self .is_leader = None
53
+ self .vote_delay = vote_delay
53
54
54
55
def make_connection (self , gossiper ):
55
56
self ._gossiper = gossiper
57
+ self .start_election ()
56
58
57
59
def _check_consensus (self , key ):
58
60
"""Check if all peers have the same value for C{key}.
59
61
60
62
Return the value if they all have the same value, otherwise
61
63
return C{None}.
62
64
"""
63
- try :
64
- correct = self ._gossiper [key ]
65
- for peer in self ._gossiper .live_peers :
66
- value = peer [key ]
67
- if value != correct :
68
- return None
69
- except KeyError :
70
- # One peer did not even have the key.
71
- return None
72
- else :
73
- return correct
65
+ correct = self ._gossiper .get (key )
66
+ for peer in self ._gossiper .live_peers :
67
+ if not key in peer .keys ():
68
+ return None
69
+ value = peer .get (key )
70
+ if value != correct :
71
+ return None
72
+ return correct
74
73
75
74
def value_changed (self , peer , key , value ):
76
75
"""Inform about a change of a key-value pair.
@@ -85,7 +84,7 @@ def value_changed(self, peer, key, value):
85
84
if key == self .VOTE_KEY :
86
85
leader = self ._check_consensus (self .VOTE_KEY )
87
86
if leader :
88
- self ._gossiper [ self .LEADER_KEY ] = leader
87
+ self ._gossiper . set ( self .LEADER_KEY , leader )
89
88
elif key == self .LEADER_KEY :
90
89
leader = self ._check_consensus (self .LEADER_KEY )
91
90
if leader :
@@ -102,19 +101,13 @@ def _vote(self):
102
101
103
102
# Check if we're one of the peers that would like to become
104
103
# master.
105
- vote , currp = None , None
106
- try :
107
- curr = self ._gossiper [self .PRIO_KEY ]
108
- if curr is not None :
109
- vote = self ._gossiper
110
- except KeyError :
111
- pass
104
+ vote = None
105
+ curr = self ._gossiper .get (self .PRIO_KEY )
106
+ if curr is not None :
107
+ vote = self ._gossiper
112
108
113
109
for peer in self ._gossiper .live_peers :
114
- try :
115
- prio = peer [self .PRIO_KEY ]
116
- except KeyError :
117
- continue
110
+ prio = peer .get (self .PRIO_KEY )
118
111
if prio is None :
119
112
# This peer did not want to become leader.
120
113
continue
@@ -126,15 +119,9 @@ def _vote(self):
126
119
vote = peer
127
120
elif prio == curr :
128
121
# We need to break the tie.
129
- if hash (peer ) > hash (vote ):
122
+ if hash (peer . name ) > hash (vote . name ):
130
123
vote = peer
131
-
132
- # See if there's a need to change our vote, or if we'll stand
133
- # by our last vote.
134
- if self .VOTE_KEY in self ._gossiper :
135
- if self ._gossiper [self .VOTE_KEY ] == vote .name :
136
- return
137
- self ._gossiper [self .VOTE_KEY ] = vote .name
124
+ self ._gossiper .set (self .VOTE_KEY , vote .name )
138
125
139
126
def start_election (self ):
140
127
"""Start an election.
@@ -155,6 +142,7 @@ def leader_elected(self, is_leader, leader):
155
142
@param is_leader: C{True} if this peer is the leader.
156
143
@param leader: The address of the peer that is the leader.
157
144
"""
145
+ self .is_leader = is_leader
158
146
159
147
def peer_dead (self , peer ):
160
148
"""A peer is dead."""
@@ -186,26 +174,39 @@ def __init__(self, clock, storage, ignore_keys=[]):
186
174
def make_connection (self , gossiper ):
187
175
self ._gossiper = gossiper
188
176
189
- def value_changed (self , peer , key , timestamp_value ):
190
- """A peer has changed its value."""
191
- if key == '__heartbeat__' :
192
- # We do not care about updates to the heartbeat value.
193
- return
194
- timestamp , value = timestamp_value
177
+ def persist_key_value (self , key , timestamped_value ):
178
+ self ._storage [key ] = timestamped_value
179
+ if hasattr (self ._storage , 'sync' ):
180
+ self ._storage .sync ()
181
+
182
+ def replicate_key_value (self , peer , key , timestamped_value ):
183
+ timestamp , value = timestamped_value
195
184
if key in self ._storage :
196
185
current_timestamp , current_value = self ._storage [key ]
197
186
if timestamp <= current_timestamp :
198
187
return
199
- self ._storage [key ] = (timestamp , value )
188
+ self ._gossiper .set (key , timestamped_value )
189
+
190
+ def value_changed (self , peer , key , timestamp_value ):
191
+ """A peer has changed its value."""
192
+ if key == '__heartbeat__' or key in self ._ignore_keys :
193
+ return
194
+ if peer .name == self ._gossiper .name :
195
+ self .persist_key_value (key , timestamp_value )
196
+ else :
197
+ self .replicate_key_value (peer , key , timestamp_value )
198
+
199
+ def set (self , key , value ):
200
+ self ._gossiper .set (key , [self .clock .seconds (), value ])
200
201
201
202
def __setitem__ (self , key , value ):
202
- self ._gossiper [ key ] = ( self . clock . seconds () , value )
203
+ self .set ( key , value )
203
204
204
205
def __getitem__ (self , key ):
205
- return self ._storage [ key ] [1 ]
206
+ return self ._gossiper . get ( key ) [1 ]
206
207
207
208
def get (self , key , default = None ):
208
- if key in self ._storage :
209
+ if key in self .keys () :
209
210
return self [key ]
210
211
return default
211
212
@@ -218,19 +219,16 @@ def keys(self, pattern=None):
218
219
return [key for key in keys
219
220
if fnmatch .fnmatch (key , pattern )]
220
221
222
+ def load_from (self , storage ):
223
+ for key in storage :
224
+ if key not in self ._ignore_keys :
225
+ self ._gossiper .set (key , storage [key ])
226
+
221
227
def __contains__ (self , key ):
222
228
return key in self .keys ()
223
229
224
- def timestamp_for_key (self , key ):
225
- return self ._storage [key ][0 ]
226
-
227
- def synchronize_keys_with_peer (self , peer ):
228
- """Synchronize keys with C{peer}.
230
+ def peer_dead (self , peer ):
231
+ """A peer is dead."""
229
232
230
- Will iterate through all the keys that C{peer} has and see if
231
- there's some values that are newer than ours.
232
- """
233
- for key , value in peer .items ():
234
- if key in self ._ignore_keys :
235
- continue
236
- self .value_changed (peer , key , value )
233
+ def peer_alive (self , peer ):
234
+ """A peer is alive."""
0 commit comments