Skip to content

Commit 46066af

Browse files
committed
Make buildable, add initial implementation, abstract the concept of a term
1 parent e1f24f5 commit 46066af

File tree

3 files changed

+118
-13
lines changed

3 files changed

+118
-13
lines changed

lib/raft/Makefile

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
CAMLP4=
22

3-
OCAMLDEP_OPTS=
3+
OCAMLDEP_OPTS= -package core
44
OCAMLC_OPTS=$(OCAMLDEP_OPTS)
55
OCAMLOPT_OPTS=$(OCAMLDEP_OPTS)
66

7-
LIB_MODULES=
7+
LIB_MODULES=raft.ml
88
NON_LIB_MODULES=
99

10-
BYTE_TARGETS=
11-
NATIVE_TARGETS=
10+
BYTE_TARGETS=raft.cma
11+
NATIVE_TARGETS=raft.cmxa
1212

1313
.PHONY: all test
1414

lib/raft/raft.ml

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
module Term = struct
2+
type t = Num.num
3+
4+
let zero = Num.num_of_int 0
5+
let succ = Num.succ_num
6+
let compare = Num.compare_num
7+
let of_string = Num.num_of_string
8+
let to_string = Num.string_of_num
9+
end
10+
11+
module type LOG = sig
12+
type elt
13+
type t
14+
15+
val append : elt -> t -> t option
16+
val last_term : t -> Term.t
17+
end
18+
19+
module type SERVER = sig
20+
type t
21+
22+
val equal : t -> t -> bool
23+
end
24+
25+
module Make = functor (Server : SERVER) -> functor (Log : LOG) -> struct
26+
type 'a t = { voted_for : Server.t option
27+
; votes : Server.t list
28+
; me : Server.t
29+
; servers : Server.t list
30+
; current_term : Term.t
31+
; log : Log.t
32+
; leader : Server.t option
33+
}
34+
35+
36+
type error = [ `Bad_term | `Bad_previous ]
37+
38+
let create ~me ~log servers =
39+
{ voted_for = None
40+
; votes = []
41+
; me = me
42+
; servers = servers
43+
; current_term = Log.last_term log
44+
; log = log
45+
; leader = None
46+
}
47+
48+
let servers t = t.servers
49+
50+
let current_term t = t.current_term
51+
52+
let voted_for t = t.voted_for
53+
54+
let log t = t.log
55+
56+
let set_log log t = { t with log = log }
57+
58+
let leader t = t.leader
59+
60+
let heartbeat_timeout t = { t with voted_for = None; leader = None }
61+
62+
let election_timeout t = { t with votes = [] }
63+
64+
let request_vote server = function
65+
| { voted_for = None } as t -> Some { t with voted_for = Some server }
66+
| _ -> None
67+
68+
let receive_vote server t = { t with votes = server::t.votes }
69+
70+
let is_now_leader t =
71+
if List.length t.votes > (List.length t.servers / 2) then
72+
Some { t with votes = []; leader = Some t.me }
73+
else
74+
None
75+
76+
77+
let receive_log _ _ = failwith "nyi"
78+
let append_log _ _ = failwith "nyi"
79+
80+
end

lib/raft/raft.mli

+34-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
1+
module Term : sig
2+
type t
3+
4+
val zero : t
5+
val succ : t -> t
6+
val compare : t -> t -> int
7+
val of_string : string -> t
8+
val to_string : t -> string
9+
end
10+
111
module type LOG = sig
212
type elt
313
type t
414

5-
val append : elt -> t -> t option
15+
val append : elt -> t -> t option
16+
val last_term : t -> Term.t
617
end
718

819
module type SERVER = sig
@@ -13,29 +24,43 @@ end
1324

1425
module Make : functor (Server : SERVER) -> functor (Log : LOG) -> sig
1526
type 'a t
27+
type error = [ `Bad_term | `Bad_previous ]
1628

17-
val create : Server.t list -> [ `Follower ] t
29+
val create : me:Server.t -> log:Log.t -> Server.t list -> [ `Follower ] t
1830

1931
val servers : 'a t -> Server.t list
20-
val set_servers : Server.t list -> 'a t -> 'a t
2132

22-
val current_term : 'a t -> int
33+
val current_term : 'a t -> Term.t
2334
val voted_for : 'a t -> Server.t option
2435

2536
val log : 'a t -> Log.t
37+
val set_log : Log.t -> 'a t -> 'a t
2638

2739
val leader : 'a t -> Server.t option
2840

29-
val next_index : [ `Leader ] t -> (Server.t * int) list
30-
val match_index : [ `Leader ] t -> (Server.t * int) list
31-
41+
(*
42+
* Triggered when we are a follower and have not heard from the leader
43+
* in some timeout period
44+
*)
3245
val heartbeat_timeout : [ `Follower] t -> [ `Candidate ] t
3346

47+
(*
48+
* This set of functions are used during a voting round
49+
*
50+
* request_vote - A server is requesting a vote from us. Returns [t option]
51+
* if it is granted and None if it is not
52+
*
53+
* receive_vote - A vote has been requested and received from the server
54+
*
55+
* is_now_leader - Tests if the current state machine can become a leader.
56+
* If so, return it.
57+
*)
3458
val election_timeout : [ `Candidate ] t -> [ `Candidate ] t
35-
val receive_vote : [ `Candidate ] t -> [ `Candidate ] t
59+
val request_vote : Server.t -> [ `Follower ] t -> [ `Follower ] t option
60+
val receive_vote : Server.t -> [ `Candidate ] t -> [ `Candidate ] t
3661
val is_now_leader : [ `Candidate ] t -> [ `Leader ] t option
3762

38-
val receive_log : Log.t -> 'a t -> [ `Follower ] t
63+
val receive_log : Log.t -> [ `Candidate | `Follower ] t -> ([ `Follower ] t, [> error ]) Core.Result.t
3964
val append_log : Log.t -> [ `Leader ] t -> [ `Leader ] t
4065

4166
end

0 commit comments

Comments
 (0)