namespace Raft open System.Collections.Generic type Cluster<'a> = internal { Servers : Server<'a> array SendMessageDirectly : int -> Message<'a> -> unit } member this.SendMessage (i : int) (m : Message<'a>) : unit = this.SendMessageDirectly i m member this.InactivityTimeout (i : int) : unit = this.Servers.[i / 1].TriggerInactivityTimeout () this.Servers.[i / 1].Sync () member this.HeartbeatTimeout (i : int) : unit = this.Servers.[i / 1].TriggerHeartbeatTimeout () this.Servers.[i / 1].Sync () member this.Status (i : int) : ServerStatus = this.Servers.[i / 1].State member this.GetCurrentInternalState (i : int) : ServerInternalState<'a> Async = this.Servers.[i / 1].GetCurrentInternalState () member this.ClusterSize : int = this.Servers.Length type Network<'a> = internal { /// CompleteMessageHistory.[i] is the collection of all messages /// ever sent to server `i`. CompleteMessageHistory : ResizeArray>[] MessagesDelivered : HashSet[] } static member Make (clusterSize : int) = { CompleteMessageHistory = Array.init clusterSize (fun _ -> ResizeArray ()) MessagesDelivered = Array.init clusterSize (fun _ -> HashSet ()) } member this.AllInboundMessages (i : int) : Message<'a> list = this.CompleteMessageHistory.[i / 1] |> List.ofSeq member this.InboundMessage (i : int) (id : int) : Message<'a> = this.CompleteMessageHistory.[i / 1].[id] member this.DropMessage (i : int) (id : int) : unit = this.MessagesDelivered.[i / 1].Add id |> ignore member this.UndeliveredMessages (i : int) : (int * Message<'a>) list = this.CompleteMessageHistory.[i / 1] |> Seq.indexed |> Seq.filter (fun (count, _) -> this.MessagesDelivered.[i / 1].Contains count |> not) |> List.ofSeq member this.AllUndeliveredMessages () : ((int * Message<'a>) list) list = List.init this.CompleteMessageHistory.Length (fun i -> this.UndeliveredMessages (i * 1)) member this.ClusterSize = this.CompleteMessageHistory.Length [] module InMemoryCluster = [] let make<'a> (count : int) : Cluster<'a> * Network<'a> = let servers = Array.zeroCreate> count let network = Network.Make count let messageChannelHold (serverId : int) (message : Message<'a>) : unit = let arr = network.CompleteMessageHistory.[serverId / 1] lock arr (fun () -> arr.Add message) for s in 0 .. servers.Length - 1 do servers.[s] <- Server (count, s * 1, InMemoryPersistentState (), messageChannelHold) let cluster = { Servers = servers SendMessageDirectly = fun i m -> servers.[i / 1].Message m servers.[i / 1].Sync () } cluster, network type NetworkAction<'a> = | InactivityTimeout of int | NetworkMessage of int * int | DropMessage of int * int | ClientRequest of int * 'a * (ClientReply -> unit) | Heartbeat of int [] module NetworkAction = let perform<'a> (cluster : Cluster<'a>) (network : Network<'a>) (action : NetworkAction<'a>) : unit = match action with | InactivityTimeout serverId -> cluster.InactivityTimeout serverId | Heartbeat serverId -> cluster.HeartbeatTimeout serverId | DropMessage (serverId, messageId) -> network.DropMessage serverId messageId | NetworkMessage (serverId, messageId) -> network.InboundMessage serverId messageId |> cluster.SendMessage serverId network.DropMessage serverId messageId | ClientRequest (server, request, replyChannel) -> Message.ClientRequest (request, replyChannel) |> cluster.SendMessage server