Format with Fantomas

This commit is contained in:
Smaug123
2022-10-24 12:59:55 +01:00
parent dd26730c67
commit 9fc2ad6f22
3 changed files with 50 additions and 36 deletions

View File

@@ -10,16 +10,14 @@ module TestServer =
[<Test>] [<Test>]
let foo () = let foo () =
let cluster = InMemoryCluster.make<int> 5 let cluster = InMemoryCluster.make<int> 5
let logger, logs = let logger, logs =
let logs = ResizeArray () let logs = ResizeArray ()
let logLine (s : string) = let logLine (s : string) = lock logs (fun () -> logs.Add s)
lock logs (fun () ->
logs.Add s
)
let freezeLogs () = let freezeLogs () =
lock logs (fun () -> lock logs (fun () -> logs |> Seq.toList)
logs |> Seq.toList
)
logLine, freezeLogs logLine, freezeLogs
let sendMessage = cluster.Servers.[0].OutboundMessageChannel let sendMessage = cluster.Servers.[0].OutboundMessageChannel
@@ -29,15 +27,10 @@ module TestServer =
{ {
CandidateTerm = 0<Term> CandidateTerm = 0<Term>
CandidateId = 1<ServerId> CandidateId = 1<ServerId>
ReplyChannel = ReplyChannel = fun message -> logger (sprintf "Received message for term %i" message.VoterTerm)
fun message ->
logger (sprintf "Received message for term %i" message.VoterTerm)
CandidateLastLogEntry = 0<LogIndex>, 0<Term> CandidateLastLogEntry = 0<LogIndex>, 0<Term>
} }
|> Message.RequestVote |> Message.RequestVote
|> sendMessage 0<ServerId> |> sendMessage 0<ServerId>
logs () logs () |> shouldEqual [ "Received message for term 0" ]
|> shouldEqual [
"Received message for term 0"
]

View File

@@ -2,6 +2,6 @@ namespace Raft.AssemblyInfo
open System.Runtime.CompilerServices open System.Runtime.CompilerServices
[<assembly: InternalsVisibleTo("Raft.Test")>] [<assembly : InternalsVisibleTo("Raft.Test")>]
do () do ()

View File

@@ -1,9 +1,14 @@
namespace Raft namespace Raft
/// LogIndex is indexed from 1. We use 0 to indicate "before any history has started". /// LogIndex is indexed from 1. We use 0 to indicate "before any history has started".
[<Measure>] type LogIndex [<Measure>]
[<Measure>] type Term type LogIndex
[<Measure>] type ServerId
[<Measure>]
type Term
[<Measure>]
type ServerId
/// Server state which need not survive a server crash. /// Server state which need not survive a server crash.
type VolatileState = type VolatileState =
@@ -63,6 +68,12 @@ type AppendEntriesReply =
Success : bool Success : bool
} }
type LogEntry =
{
Index : int<LogIndex>
Term : int<Term>
}
/// I am the leader. Followers, update your state as follows. /// I am the leader. Followers, update your state as follows.
type AppendEntriesMessage<'a> = type AppendEntriesMessage<'a> =
{ {
@@ -71,7 +82,7 @@ type AppendEntriesMessage<'a> =
/// I am your leader! This is me! (so everyone knows where to send clients to) /// I am your leader! This is me! (so everyone knows where to send clients to)
LeaderId : int<ServerId> LeaderId : int<ServerId>
/// The entry immediately preceding the entry I'm sending you, so you can tell if we've got out of sync. /// The entry immediately preceding the entry I'm sending you, so you can tell if we've got out of sync.
PrevLogEntry : {| Index : int<LogIndex> ; Term : int<Term> |} PrevLogEntry : LogEntry
/// Followers, append this entry to your log. (Or, if None, this is just a heartbeat.) /// Followers, append this entry to your log. (Or, if None, this is just a heartbeat.)
/// It was determined at the given term - recall that we might need to bring a restarted node up to speed /// It was determined at the given term - recall that we might need to bring a restarted node up to speed
/// with what happened during terms that took place while it was down. /// with what happened during terms that took place while it was down.
@@ -83,6 +94,7 @@ type AppendEntriesMessage<'a> =
type Message<'a> = type Message<'a> =
| AppendEntries of AppendEntriesMessage<'a> | AppendEntries of AppendEntriesMessage<'a>
| RequestVote of RequestVoteMessage | RequestVote of RequestVoteMessage
member this.Term = member this.Term =
match this with match this with
| AppendEntries m -> m.LeaderTerm | AppendEntries m -> m.LeaderTerm
@@ -106,12 +118,10 @@ type Server<'a> =
module Server = module Server =
let inline private getLogEntry<'a> (index : int<LogIndex>) (arr : 'a array) : 'a option = let inline private getLogEntry<'a> (index : int<LogIndex>) (arr : 'a array) : 'a option =
arr arr |> Array.tryItem ((index - 1<LogIndex>) / 1<LogIndex>)
|> Array.tryItem ((index - 1<LogIndex>) / 1<LogIndex>)
let inline private truncateLog<'a> (finalIndex : int<LogIndex>) (arr : 'a array) : 'a array = let inline private truncateLog<'a> (finalIndex : int<LogIndex>) (arr : 'a array) : 'a array =
arr arr |> Array.truncate (finalIndex / 1<LogIndex>)
|> Array.truncate (finalIndex / 1<LogIndex>)
let inline private replaceLog<'a> (index : int<LogIndex>) (elt : 'a) (arr : 'a array) : 'a array = let inline private replaceLog<'a> (index : int<LogIndex>) (elt : 'a) (arr : 'a array) : 'a array =
let toRet = Array.copy arr let toRet = Array.copy arr
@@ -151,8 +161,9 @@ module Server =
CurrentTerm = message.Term CurrentTerm = message.Term
} }
} }
// TODO when persistence is modelled: persist this // TODO when persistence is modelled: persist this
else s else
s
match message with match message with
| RequestVote message -> | RequestVote message ->
@@ -166,8 +177,7 @@ module Server =
// Is the candidate advertising a later term than our last-persisted write was made at? // Is the candidate advertising a later term than our last-persisted write was made at?
// (That would mean it's far in the future of us.) // (That would mean it's far in the future of us.)
match Array.tryLast s.PersistentState.Log with match Array.tryLast s.PersistentState.Log with
| Some (_, ourLastTerm) -> | Some (_, ourLastTerm) -> snd message.CandidateLastLogEntry > ourLastTerm
snd message.CandidateLastLogEntry > ourLastTerm
| None -> | None ->
// We have persisted no history at all! // We have persisted no history at all!
true true
@@ -177,7 +187,8 @@ module Server =
match Array.tryLast s.PersistentState.Log with match Array.tryLast s.PersistentState.Log with
| Some (_, ourLastTerm) -> | Some (_, ourLastTerm) ->
snd message.CandidateLastLogEntry = ourLastTerm snd message.CandidateLastLogEntry = ourLastTerm
&& fst message.CandidateLastLogEntry >= (Array.length s.PersistentState.Log) * 1<LogIndex> && fst message.CandidateLastLogEntry
>= (Array.length s.PersistentState.Log) * 1<LogIndex>
| None -> | None ->
// We've persisted no history; the candidate needs to also be at the start of history, // We've persisted no history; the candidate needs to also be at the start of history,
// or else we'd have already considered them in the `messageSupersedesMe` check. // or else we'd have already considered them in the `messageSupersedesMe` check.
@@ -257,7 +268,12 @@ module Server =
let heartbeat (message : AppendEntriesMessage<'a>) (s : Server<'a>) = let heartbeat (message : AppendEntriesMessage<'a>) (s : Server<'a>) =
// Just a heartbeat; no change to our log is required. // Just a heartbeat; no change to our log is required.
let toReturn = let toReturn =
{ s with VolatileState = { s.VolatileState with CommitIndex = message.LeaderCommitIndex } } { s with
VolatileState =
{ s.VolatileState with
CommitIndex = message.LeaderCommitIndex
}
}
{ {
Success = true Success = true
@@ -370,7 +386,10 @@ module Server =
| Candidate -> | Candidate ->
// We've already verified that the message was sent from a leader in the current term, so we have // We've already verified that the message was sent from a leader in the current term, so we have
// lost the election. // lost the election.
let s = { s with Type = Follower } let s =
{ s with
Type = Follower
}
// TODO: why does this assertion hold? // TODO: why does this assertion hold?
assert (logIsConsistent message s) assert (logIsConsistent message s)
acceptRequest s acceptRequest s
@@ -392,12 +411,14 @@ module InMemoryCluster =
let locker = obj () let locker = obj ()
let messageChannel (serverId : int<ServerId>) (message : Message<'a>) : unit = let messageChannel (serverId : int<ServerId>) (message : Message<'a>) : unit =
lock locker (fun () -> lock
let newServer = Server.processMessage message servers.[serverId / 1<ServerId>] locker
servers.[serverId / 1<ServerId>] <- newServer (fun () ->
) let newServer = Server.processMessage message servers.[serverId / 1<ServerId>]
servers.[serverId / 1<ServerId>] <- newServer
)
for s in 0..servers.Length - 1 do for s in 0 .. servers.Length - 1 do
servers.[s] <- Server.create messageChannel servers.[s] <- Server.create messageChannel
{ {