raft 0.0.3 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|