raft 0.0.3 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/raft.rb +35 -8
  3. data/lib/raft/goliath.rb +6 -3
  4. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b93e1acac92fc590e669fd765e13da401bd03649
4
- data.tar.gz: 292865e0af4c1a662a3b07fbfeb7d4905af8e195
3
+ metadata.gz: 8fb71b1c5a8ec7d92e83aa96fbf5dcd50e1e1618
4
+ data.tar.gz: 6a68f46a38f513a37f719f449f1c6465942a355d
5
5
  SHA512:
6
- metadata.gz: eb2440b0e811a0a557ae32da8d3024b80e61c8fb45b870836adb15a5d36e0fd578e54459234f113d220f6442504347ed5b3c0cbdb405879cca4c4d2d3b9ef1b0
7
- data.tar.gz: f97c12da642745009b5811e38ec584ed40b66687a44ff10effb58d2182a0078787126c3baefc7ba4b5ea351d3e7fa4ebeda16c03cdb3de98a0e20ba2696395e4
6
+ metadata.gz: 962aa0264a180e89e09d4473d5dd8cee8c9d3e8e7ad99a36d784381abe757fa4f6b484aa265516c3a67e3b112b003448b1bb6a8954de6f3456925107d2916eba
7
+ data.tar.gz: b2d783f93630ca150a6b8cebb77c21a5251775d28862665e768f780ed3bd92cedb5593332f2c46c9ac6be7d1a9ae35bba4b69b722333cca6904c3c207720569a
@@ -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
- @start = Time.now - interval
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("\nsending heartbeats\n")
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
 
@@ -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.0.3
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: []