raft 0.0.3 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/raft.rb +35 -8
- data/lib/raft/goliath.rb +6 -3
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8fb71b1c5a8ec7d92e83aa96fbf5dcd50e1e1618
|
4
|
+
data.tar.gz: 6a68f46a38f513a37f719f449f1c6465942a355d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 962aa0264a180e89e09d4473d5dd8cee8c9d3e8e7ad99a36d784381abe757fa4f6b484aa265516c3a67e3b112b003448b1bb6a8954de6f3456925107d2916eba
|
7
|
+
data.tar.gz: b2d783f93630ca150a6b8cebb77c21a5251775d28862665e768f780ed3bd92cedb5593332f2c46c9ac6be7d1a9ae35bba4b69b722333cca6904c3c207720569a
|
data/lib/raft.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'delegate'
|
2
2
|
|
3
3
|
module Raft
|
4
|
-
Config = Struct.new(:rpc_provider, :async_provider, :election_timeout, :update_interval, :heartbeat_interval)
|
4
|
+
Config = Struct.new(:rpc_provider, :async_provider, :election_timeout, :election_splay, :update_interval, :heartbeat_interval)
|
5
5
|
|
6
6
|
class Cluster
|
7
7
|
attr_reader :node_ids
|
@@ -21,6 +21,22 @@ module Raft
|
|
21
21
|
def initialize(term, index, command)
|
22
22
|
@term, @index, @command = term, index, command
|
23
23
|
end
|
24
|
+
|
25
|
+
def ==(other)
|
26
|
+
[:term, :index, :command].all? do |attr|
|
27
|
+
self.send(attr) == other.send(attr)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def eql?(other)
|
32
|
+
self == other
|
33
|
+
end
|
34
|
+
|
35
|
+
def hash
|
36
|
+
[:term, :index, :command].reduce(0) do |h, attr|
|
37
|
+
h ^= self.send(attr)
|
38
|
+
end
|
39
|
+
end
|
24
40
|
end
|
25
41
|
|
26
42
|
class Log < DelegateClass(Array)
|
@@ -129,13 +145,19 @@ module Raft
|
|
129
145
|
end
|
130
146
|
|
131
147
|
class Timer
|
132
|
-
def initialize(interval)
|
133
|
-
@interval = interval
|
134
|
-
@
|
148
|
+
def initialize(interval, splay=0.0)
|
149
|
+
@interval = interval.to_f
|
150
|
+
@splay = splay.to_f
|
151
|
+
@start = Time.now - @interval + (rand * @splay)
|
152
|
+
end
|
153
|
+
|
154
|
+
def splayed_interval
|
155
|
+
(@interval + (rand * @splay))#.tap {|t|STDOUT.write("\nsplayed interval is #{t}\n")}
|
135
156
|
end
|
136
157
|
|
137
158
|
def reset!
|
138
|
-
@start = Time.now
|
159
|
+
@start = Time.now + splayed_interval
|
160
|
+
#STDOUT.write("\ntimer will elapse at #{timeout.strftime('%H:%M:%S:%L')} (timeout is #{timeout.class})\n")
|
139
161
|
end
|
140
162
|
|
141
163
|
def timeout
|
@@ -143,6 +165,7 @@ module Raft
|
|
143
165
|
end
|
144
166
|
|
145
167
|
def timed_out?
|
168
|
+
#STDOUT.write("\ntime is #{Time.now.strftime('%M:%S:%L')}\n")
|
146
169
|
Time.now > timeout
|
147
170
|
end
|
148
171
|
end
|
@@ -167,7 +190,7 @@ module Raft
|
|
167
190
|
@cluster = cluster
|
168
191
|
@persistent_state = PersistentState.new
|
169
192
|
@temporary_state = TemporaryState.new(nil, nil)
|
170
|
-
@election_timer = Timer.new(config.election_timeout)
|
193
|
+
@election_timer = Timer.new(config.election_timeout, config.election_splay)
|
171
194
|
@commit_handler = commit_handler || (block.to_proc if block_given?)
|
172
195
|
end
|
173
196
|
|
@@ -189,6 +212,7 @@ module Raft
|
|
189
212
|
|
190
213
|
def follower_update
|
191
214
|
if @election_timer.timed_out?
|
215
|
+
#STDOUT.write("follower node #{@id} election timed out at #{Time.now.strftime('%H:%M:%S:%L')}\n")
|
192
216
|
@role = CANDIDATE_ROLE
|
193
217
|
candidate_update
|
194
218
|
end
|
@@ -198,6 +222,7 @@ module Raft
|
|
198
222
|
|
199
223
|
def candidate_update
|
200
224
|
if @election_timer.timed_out?
|
225
|
+
#STDOUT.write("candidate node #{@id} election timed out at #{Time.now.strftime('%H:%M:%S:%L')}\n")
|
201
226
|
@persistent_state.current_term += 1
|
202
227
|
@persistent_state.voted_for = @id
|
203
228
|
reset_election_timeout
|
@@ -288,7 +313,7 @@ module Raft
|
|
288
313
|
protected :establish_leadership
|
289
314
|
|
290
315
|
def send_heartbeats
|
291
|
-
#STDOUT.write("\
|
316
|
+
#STDOUT.write("\nnode #{@id} sending heartbeats at #{Time.now.strftime('%H:%M:%S:%L')}\n")
|
292
317
|
last_log_entry = @persistent_state.log.last
|
293
318
|
log_index = last_log_entry ? last_log_entry.index : nil
|
294
319
|
log_term = last_log_entry ? last_log_entry.term : nil
|
@@ -346,6 +371,7 @@ module Raft
|
|
346
371
|
protected :append_entries_to_follower
|
347
372
|
|
348
373
|
def handle_request_vote(request)
|
374
|
+
#STDOUT.write("\nnode #{@id} handling vote request from #{request.candidate_id}\n")
|
349
375
|
response = RequestVoteResponse.new
|
350
376
|
response.term = @persistent_state.current_term
|
351
377
|
response.vote_granted = false
|
@@ -381,11 +407,12 @@ module Raft
|
|
381
407
|
end
|
382
408
|
|
383
409
|
def handle_append_entries(request)
|
384
|
-
#STDOUT.write("\n\nnode #{@id} handle_append_entries: #{request.entries.pretty_inspect}\n\n") if request.prev_log_index.nil?
|
410
|
+
#STDOUT.write("\n\nnode #{@id} handle_append_entries: #{request.entries.pretty_inspect}\n\n") #if request.prev_log_index.nil?
|
385
411
|
response = AppendEntriesResponse.new
|
386
412
|
response.term = @persistent_state.current_term
|
387
413
|
response.success = false
|
388
414
|
|
415
|
+
#STDOUT.write("\n\nnode #{@id} handle_append_entries for term #{request.term} (current is #{@persistent_state.current_term})\n")# if request.prev_log_index.nil?
|
389
416
|
return response if request.term < @persistent_state.current_term
|
390
417
|
#STDOUT.write("\n\nnode #{@id} handle_append_entries stage 2\n") if request.prev_log_index.nil?
|
391
418
|
|
data/lib/raft/goliath.rb
CHANGED
@@ -6,9 +6,9 @@ module Raft
|
|
6
6
|
class Goliath
|
7
7
|
|
8
8
|
def self.log(message)
|
9
|
-
STDOUT.write("\n\n")
|
10
|
-
STDOUT.write(message)
|
11
|
-
STDOUT.write("\n\n")
|
9
|
+
#STDOUT.write("\n\n")
|
10
|
+
#STDOUT.write(message)
|
11
|
+
#STDOUT.write("\n\n")
|
12
12
|
end
|
13
13
|
|
14
14
|
class HttpJsonRpcResponder < ::Goliath::API
|
@@ -36,6 +36,7 @@ module Raft
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def request_vote_response(params)
|
39
|
+
#STDOUT.write("\nnode #{@node.id} received request_vote from #{params['candidate_id']}, term #{params['term']}\n")
|
39
40
|
request = Raft::RequestVoteRequest.new(
|
40
41
|
params['term'],
|
41
42
|
params['candidate_id'],
|
@@ -46,6 +47,7 @@ module Raft
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def append_entries_response(params)
|
50
|
+
#STDOUT.write("\nnode #{@node.id} received append_entries from #{params['leader_id']}, term #{params['term']}\n")
|
49
51
|
entries = params['entries'].map {|entry| Raft::LogEntry.new(entry['term'], entry['index'], entry['command'])}
|
50
52
|
request = Raft::AppendEntriesRequest.new(
|
51
53
|
params['term'],
|
@@ -56,6 +58,7 @@ module Raft
|
|
56
58
|
params['commit_index'])
|
57
59
|
#STDOUT.write("\nnode #{@node.id} received entries: #{request.entries.pretty_inspect}\n")
|
58
60
|
response = @node.handle_append_entries(request)
|
61
|
+
#STDOUT.write("\nnode #{@node.id} completed append_entries from #{params['leader_id']}, term #{params['term']} (#{response})\n")
|
59
62
|
[200, HEADERS, { 'term' => response.term, 'success' => response.success }]
|
60
63
|
end
|
61
64
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: raft
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Harry Wilkinson
|
@@ -103,7 +103,8 @@ files:
|
|
103
103
|
- lib/raft.rb
|
104
104
|
- lib/raft/goliath.rb
|
105
105
|
homepage: http://github.com/harryw/raft
|
106
|
-
licenses:
|
106
|
+
licenses:
|
107
|
+
- MIT
|
107
108
|
metadata: {}
|
108
109
|
post_install_message:
|
109
110
|
rdoc_options: []
|