Files
raft-fable/Raft/PersistentState.fs
2022-11-13 21:44:19 +00:00

79 lines
2.7 KiB
Forth

namespace Raft
open System.Threading
type IPersistentState<'a> =
abstract CurrentTerm : int<Term>
/// If I know about an election in my CurrentTerm, who did I vote for during that election?
abstract VotedFor : int<ServerId> option
abstract AppendToLog : LogEntry<'a> -> int<Term> -> unit
/// Truncate away the most recent entries of the log.
/// If `GetLogEntry x` would succeed, and then we call `TruncateLog x`,
/// then `GetLogEntry x` will still succeed (but `GetLogEntry (x + 1)` will not).
abstract TruncateLog : int<LogIndex> -> unit
abstract GetLogEntry : int<LogIndex> -> (LogEntry<'a> * int<Term>) option
abstract CurrentLogIndex : int<LogIndex>
abstract GetLastLogEntry : unit -> (LogEntry<'a> * LogEntryMetadata) option
abstract AdvanceToTerm : int<Term> -> unit
abstract IncrementTerm : unit -> unit
abstract Vote : int<ServerId> -> unit
/// Server state which must survive a server crash.
[<Class>]
type InMemoryPersistentState<'a> () =
let mutable currentTerm = 0
let mutable votedFor : int<ServerId> option = None
let log = ResizeArray<LogEntry<'a> * int<Term>> ()
member this.GetLog () = log |> List.ofSeq
interface IPersistentState<'a> with
member this.CurrentTerm = currentTerm * 1<Term>
member this.IncrementTerm () =
#if FABLE_COMPILER
currentTerm <- currentTerm + 1
#else
Interlocked.Increment &currentTerm |> ignore
#endif
member this.VotedFor = votedFor
member this.Vote id = votedFor <- Some id
member this.AdvanceToTerm term =
currentTerm <- term / 1<Term>
votedFor <- None
member this.AppendToLog (entry : LogEntry<'a>) term = log.Add (entry, term)
member this.TruncateLog position =
let position = position / 1<LogIndex>
if position < log.Count then
let position = if position < 0 then 0 else position
log.RemoveRange (position, log.Count - position)
member this.GetLastLogEntry () : (LogEntry<'a> * LogEntryMetadata) option =
if log.Count = 0 then
None
else
let stored, term = log[log.Count - 1]
Some (
stored,
{
Index = log.Count * 1<LogIndex>
Term = term
}
)
member this.GetLogEntry position =
let position = position / 1<LogIndex>
if log.Count < position then None
elif position <= 0 then None
else Some log[position - 1]
member this.CurrentLogIndex = log.Count * 1<LogIndex>