-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Raft consensus algorithm -- -- Please see the README on GitHub at -- https://github.com/adjoint-io/raft#readme @package libraft @version 0.5.0.0 module Control.Concurrent.STM.Timer data Timer -- | Create a new timer with the supplied timer action and timer length, newTimer :: Natural -> IO Timer -- | Create a new timer with the supplied timer action, random seed, and -- range from which the the timer will choose a random timer length at -- each start or reset. newTimerRange :: Int -> (Natural, Natural) -> IO Timer -- | Start the timer. If the timer is already running, the timer is not -- started. Returns True if the timer was succesfully started. startTimer :: Timer -> IO Bool -- | Resets the timer with a new random timeout. resetTimer :: Timer -> IO () -- | Wait for a timer to complete waitTimer :: Timer -> IO () module Raft.Types -- | Unique identifier of a Raft node type NodeId = ByteString type NodeIds = Set NodeId -- | Unique identifier of a client newtype ClientId ClientId :: NodeId -> ClientId -- | Unique identifier of a leader newtype LeaderId LeaderId :: NodeId -> LeaderId [unLeaderId] :: LeaderId -> NodeId -- | Representation of the current leader in the cluster. The system is -- considered to be unavailable if there is no leader data CurrentLeader CurrentLeader :: LeaderId -> CurrentLeader NoLeader :: CurrentLeader data Mode Follower :: Mode Candidate :: Mode Leader :: Mode -- | Representation of monotonic election terms newtype Term Term :: Natural -> Term intToNatural :: Int -> Either [Char] Natural -- | Initial term. Terms start at 0 term0 :: Term incrTerm :: Term -> Term prevTerm :: Term -> Term -- | Representation of monotonic indices newtype Index Index :: Natural -> Index -- | Initial index. Indeces start at 0 index0 :: Index incrIndex :: Index -> Index -- | Decrement index. If the given index is 0, return the given index decrIndexWithDefault0 :: Index -> Index newtype SerialNum SerialNum :: Natural -> SerialNum instance Data.Serialize.Serialize Raft.Types.SerialNum instance GHC.Num.Num Raft.Types.SerialNum instance GHC.Enum.Enum Raft.Types.SerialNum instance GHC.Classes.Ord Raft.Types.SerialNum instance GHC.Classes.Eq Raft.Types.SerialNum instance GHC.Generics.Generic Raft.Types.SerialNum instance GHC.Read.Read Raft.Types.SerialNum instance GHC.Show.Show Raft.Types.SerialNum instance Data.Serialize.Serialize Raft.Types.Index instance GHC.Real.Real Raft.Types.Index instance GHC.Real.Integral Raft.Types.Index instance GHC.Num.Num Raft.Types.Index instance GHC.Enum.Enum Raft.Types.Index instance GHC.Classes.Ord Raft.Types.Index instance GHC.Classes.Eq Raft.Types.Index instance GHC.Generics.Generic Raft.Types.Index instance GHC.Read.Read Raft.Types.Index instance GHC.Show.Show Raft.Types.Index instance Data.Serialize.Serialize Raft.Types.Term instance GHC.Enum.Enum Raft.Types.Term instance GHC.Classes.Ord Raft.Types.Term instance GHC.Classes.Eq Raft.Types.Term instance GHC.Show.Show Raft.Types.Term instance GHC.Generics.Generic Raft.Types.Term instance GHC.Read.Read Raft.Types.Mode instance GHC.Show.Show Raft.Types.Mode instance Data.Serialize.Serialize Raft.Types.CurrentLeader instance GHC.Generics.Generic Raft.Types.CurrentLeader instance GHC.Classes.Eq Raft.Types.CurrentLeader instance GHC.Show.Show Raft.Types.CurrentLeader instance Data.Serialize.Serialize Raft.Types.LeaderId instance GHC.Generics.Generic Raft.Types.LeaderId instance GHC.Classes.Eq Raft.Types.LeaderId instance GHC.Read.Read Raft.Types.LeaderId instance GHC.Show.Show Raft.Types.LeaderId instance Data.Serialize.Serialize Raft.Types.ClientId instance GHC.Generics.Generic Raft.Types.ClientId instance GHC.Classes.Ord Raft.Types.ClientId instance GHC.Classes.Eq Raft.Types.ClientId instance GHC.Read.Read Raft.Types.ClientId instance GHC.Show.Show Raft.Types.ClientId instance Database.PostgreSQL.Simple.ToField.ToField Raft.Types.Index instance Database.PostgreSQL.Simple.FromField.FromField Raft.Types.Index instance Database.PostgreSQL.Simple.ToField.ToField Raft.Types.Term instance Database.PostgreSQL.Simple.FromField.FromField Raft.Types.Term module Raft.Persistent -- | Provides an interface to read and write the persistent state to disk. class Monad m => RaftPersist m where { type family RaftPersistError m; } initializePersistentState :: (RaftPersist m, Exception (RaftPersistError m)) => m (Either (RaftPersistError m) ()) readPersistentState :: (RaftPersist m, Exception (RaftPersistError m)) => m (Either (RaftPersistError m) PersistentState) writePersistentState :: (RaftPersist m, Exception (RaftPersistError m)) => PersistentState -> m (Either (RaftPersistError m) ()) -- | Persistent state that all Raft nodes maintain, regardless of node -- state. data PersistentState PersistentState :: !Term -> !Maybe NodeId -> PersistentState -- | Last term server has seen [currentTerm] :: PersistentState -> !Term -- | Candidate id that received vote in current term [votedFor] :: PersistentState -> !Maybe NodeId -- | A node initiates its persistent state with term 0 and with its vote -- blank initPersistentState :: PersistentState instance Data.Serialize.Serialize Raft.Persistent.PersistentState instance GHC.Generics.Generic Raft.Persistent.PersistentState instance GHC.Classes.Eq Raft.Persistent.PersistentState instance GHC.Show.Show Raft.Persistent.PersistentState module Raft.Log data EntryIssuer ClientIssuer :: ClientId -> SerialNum -> EntryIssuer LeaderIssuer :: LeaderId -> EntryIssuer data EntryValue v EntryValue :: v -> EntryValue v -- | Used as a first committed entry of a new term NoValue :: EntryValue v newtype EntryHash EntryHash :: ByteString -> EntryHash [unEntryHash] :: EntryHash -> ByteString genesisHash :: EntryHash hashEntry :: Serialize v => Entry v -> EntryHash -- | Representation of an entry in the replicated log data Entry v Entry :: Index -> Term -> EntryValue v -> EntryIssuer -> EntryHash -> Entry v -- | Index of entry in the log [entryIndex] :: Entry v -> Index -- | Term when entry was received by leader [entryTerm] :: Entry v -> Term -- | Command to update state machine [entryValue] :: Entry v -> EntryValue v -- | Id of the client that issued the command [entryIssuer] :: Entry v -> EntryIssuer [entryPrevHash] :: Entry v -> EntryHash type Entries v = Seq (Entry v) lastEntryIndex :: Entries v -> Maybe Index -- | The datatype representing a node's last log entry data LastLogEntry v LastLogEntry :: Entry v -> LastLogEntry v NoLogEntries :: LastLogEntry v hashLastLogEntry :: Serialize v => LastLogEntry v -> EntryHash lastLogEntryIndex :: LastLogEntry v -> Index lastLogEntryIssuer :: LastLogEntry v -> Maybe EntryIssuer lastLogEntryTerm :: LastLogEntry v -> Term lastLogEntryIndexAndTerm :: LastLogEntry v -> (Index, Term) -- | Provides an interface to initialize a fresh log entry storage class RaftInitLog m v where { type family RaftInitLogError m; } initializeLog :: RaftInitLog m v => Proxy v -> m (Either (RaftInitLogError m) ()) data ReadEntriesSpec ByIndex :: Index -> ReadEntriesSpec ByIndices :: IndexInterval -> ReadEntriesSpec -- | The result of reading one or more data ReadEntriesRes v OneEntry :: Entry v -> ReadEntriesRes v ManyEntries :: Entries v -> ReadEntriesRes v data IndexInterval IndexInterval :: Maybe Index -> Maybe Index -> IndexInterval -- | Provides an interface for nodes to read log entries from storage. class (Show (RaftReadLogError m), Monad m) => RaftReadLog m v where { type family RaftReadLogError m; } -- | Read the log at a given index readLogEntry :: (RaftReadLog m v, Exception (RaftReadLogError m)) => Index -> m (Either (RaftReadLogError m) (Maybe (Entry v))) -- | Read log entries from a specific index onwards, including the specific -- index readLogEntriesFrom :: (RaftReadLog m v, Exception (RaftReadLogError m)) => Index -> m (Either (RaftReadLogError m) (Entries v)) -- | Read the last log entry in the log readLastLogEntry :: (RaftReadLog m v, Exception (RaftReadLogError m)) => m (Either (RaftReadLogError m) (Maybe (Entry v))) -- | Read log entries from a specific index onwards, including the specific -- index readLogEntriesFrom :: (RaftReadLog m v, Exception (RaftReadLogError m)) => Index -> m (Either (RaftReadLogError m) (Entries v)) -- | Provides an interface for nodes to write log entries to storage. class (Show (RaftWriteLogError m), Monad m) => RaftWriteLog m v where { type family RaftWriteLogError m; } -- | Write the given log entries to storage writeLogEntries :: (RaftWriteLog m v, Exception (RaftWriteLogError m)) => Entries v -> m (Either (RaftWriteLogError m) ()) -- | Provides an interface for nodes to delete log entries from storage. class (Show (RaftDeleteLogError m), Monad m) => RaftDeleteLog m v where { type family RaftDeleteLogError m; } -- | Delete log entries from a given index; e.g. 'deleteLogEntriesFrom 7' -- should delete every log entry with an index >= 7. deleteLogEntriesFrom :: (RaftDeleteLog m v, Exception (RaftDeleteLogError m)) => Index -> m (Either (RaftDeleteLogError m) (DeleteSuccess v)) data DeleteSuccess v DeleteSuccess :: DeleteSuccess v type RaftLog m v = (RaftInitLog m v, RaftReadLog m v, RaftWriteLog m v, RaftDeleteLog m v) -- | Representation of possible errors that come from reading, writing or -- deleting logs from the persistent storage data RaftLogError m type RaftLogExceptions m = (Exception (RaftInitLogError m), Exception (RaftReadLogError m), Exception (RaftWriteLogError m), Exception (RaftDeleteLogError m)) updateLog :: forall m v. (RaftDeleteLog m v, Exception (RaftDeleteLogError m), RaftWriteLog m v, Exception (RaftWriteLogError m)) => Entries v -> m (Either (RaftLogError m) (Maybe Index)) clientReqData :: Entries v -> Map ClientId (SerialNum, Index) readEntries :: forall m v. (RaftReadLog m v, Exception (RaftReadLogError m)) => ReadEntriesSpec -> m (Either (ReadEntriesError m) (ReadEntriesRes v)) instance Data.Serialize.Serialize Raft.Log.ReadEntriesSpec instance GHC.Generics.Generic Raft.Log.ReadEntriesSpec instance GHC.Show.Show Raft.Log.ReadEntriesSpec instance Data.Serialize.Serialize Raft.Log.IndexInterval instance GHC.Generics.Generic Raft.Log.IndexInterval instance GHC.Show.Show Raft.Log.IndexInterval instance GHC.Show.Show Raft.Log.InvalidLog instance GHC.Show.Show v => GHC.Show.Show (Raft.Log.LastLogEntry v) instance Data.Serialize.Serialize v => Data.Serialize.Serialize (Raft.Log.Entry v) instance GHC.Generics.Generic (Raft.Log.Entry v) instance GHC.Classes.Eq v => GHC.Classes.Eq (Raft.Log.Entry v) instance GHC.Show.Show v => GHC.Show.Show (Raft.Log.Entry v) instance Data.Serialize.Serialize Raft.Log.EntryHash instance GHC.Generics.Generic Raft.Log.EntryHash instance GHC.Classes.Ord Raft.Log.EntryHash instance GHC.Classes.Eq Raft.Log.EntryHash instance GHC.Read.Read Raft.Log.EntryHash instance GHC.Show.Show Raft.Log.EntryHash instance Data.Serialize.Serialize v => Data.Serialize.Serialize (Raft.Log.EntryValue v) instance GHC.Generics.Generic (Raft.Log.EntryValue v) instance GHC.Classes.Eq v => GHC.Classes.Eq (Raft.Log.EntryValue v) instance GHC.Show.Show v => GHC.Show.Show (Raft.Log.EntryValue v) instance Data.Serialize.Serialize Raft.Log.EntryIssuer instance GHC.Generics.Generic Raft.Log.EntryIssuer instance GHC.Classes.Eq Raft.Log.EntryIssuer instance GHC.Read.Read Raft.Log.EntryIssuer instance GHC.Show.Show Raft.Log.EntryIssuer instance GHC.Show.Show (Raft.Log.RaftLogError m) instance GHC.Show.Show (Raft.Log.ReadEntriesError m) instance Data.Typeable.Internal.Typeable m => GHC.Exception.Type.Exception (Raft.Log.ReadEntriesError m) instance Database.PostgreSQL.Simple.ToField.ToField Raft.Log.EntryHash instance Database.PostgreSQL.Simple.FromField.FromField Raft.Log.EntryHash instance Data.Serialize.Serialize v => Database.PostgreSQL.Simple.ToField.ToField (Raft.Log.EntryValue v) instance (Data.Typeable.Internal.Typeable v, Data.Serialize.Serialize v) => Database.PostgreSQL.Simple.FromField.FromField (Raft.Log.EntryValue v) instance Database.PostgreSQL.Simple.ToField.ToField Raft.Log.EntryIssuer instance Database.PostgreSQL.Simple.FromField.FromField Raft.Log.EntryIssuer module Raft.StateMachine -- | Interface to handle commands in the underlying state machine. -- Functional dependency permitting only a single state machine command -- to be defined to update the state machine. class RaftStateMachinePure sm v | sm -> v where { data family RaftStateMachinePureError sm v; type family RaftStateMachinePureCtx sm v = ctx | ctx -> sm v; } rsmTransition :: RaftStateMachinePure sm v => RaftStateMachinePureCtx sm v -> sm -> v -> Either (RaftStateMachinePureError sm v) sm class (Monad m, RaftStateMachinePure sm v) => RaftStateMachine m sm v -- | Expensive validation using global state not cacheable in -- RaftStateMachinePureCtx validateCmd :: RaftStateMachine m sm v => v -> m (Either (RaftStateMachinePureError sm v) ()) -- | Some state machines need the leader to preprocess commands issued by -- client; e.g. attaching a timestamp before creating the log entry preprocessCmd :: RaftStateMachine m sm v => v -> m v -- | Query the RaftStateMachinePureCtx value from the monadic -- context askRaftStateMachinePureCtx :: RaftStateMachine m sm v => m (RaftStateMachinePureCtx sm v) -- | Some state machines need the leader to preprocess commands issued by -- client; e.g. attaching a timestamp before creating the log entry preprocessCmd :: RaftStateMachine m sm v => v -> m v data EntryValidation NoMonadicValidation :: EntryValidation MonadicValidation :: EntryValidation -- | Apply a log entry to the supplied state machine, allowing the user to -- specify whether or not to monadically validate the command in addition -- to the pure validation logic. -- -- This function first unwraps the log entry to see if it is a no-op or -- contains an actual state machine command to apply. applyLogEntry :: RaftStateMachine m sm v => EntryValidation -> sm -> Entry v -> m (Either (RaftStateMachinePureError sm v) sm) -- | Apply a state machine command to the supplied state machine, allowing -- the user to specify whether or not to monadically validate the command -- in addition to the pure validation logic. applyLogCmd :: forall sm cmd m. RaftStateMachine m sm cmd => EntryValidation -> sm -> cmd -> m (Either (RaftStateMachinePureError sm cmd) sm) module Raft.RPC -- | Interface for nodes to send messages to one another. E.g. -- Control.Concurrent.Chan, Network.Socket, etc. class RaftSendRPC m v sendRPC :: RaftSendRPC m v => NodeId -> RPCMessage v -> m () -- | Interface for nodes to receive messages from one another class Show (RaftRecvRPCError m v) => RaftRecvRPC m v where { type family RaftRecvRPCError m v; } receiveRPC :: RaftRecvRPC m v => m (Either (RaftRecvRPCError m v) (RPCMessage v)) -- | Representation of a message sent between nodes data RPCMessage v RPCMessage :: NodeId -> RPC v -> RPCMessage v [sender] :: RPCMessage v -> NodeId [rpc] :: RPCMessage v -> RPC v data RPC v AppendEntriesRPC :: AppendEntries v -> RPC v AppendEntriesResponseRPC :: AppendEntriesResponse -> RPC v RequestVoteRPC :: RequestVote -> RPC v RequestVoteResponseRPC :: RequestVoteResponse -> RPC v class RPCType a v toRPC :: RPCType a v => a -> RPC v rpcTerm :: RPC v -> Term data NoEntriesSpec FromHeartbeat :: NoEntriesSpec FromClientReadReq :: Int -> NoEntriesSpec data AppendEntriesSpec v FromIndex :: Index -> AppendEntriesSpec v FromNewLeader :: Entry v -> AppendEntriesSpec v FromClientWriteReq :: Entry v -> AppendEntriesSpec v NoEntries :: NoEntriesSpec -> AppendEntriesSpec v -- | The data used to construct an AppendEntries value, snapshotted from -- the node state at the time the AppendEntries val should be created. data AppendEntriesData v AppendEntriesData :: Term -> Index -> AppendEntriesSpec v -> AppendEntriesData v [aedTerm] :: AppendEntriesData v -> Term [aedLeaderCommit] :: AppendEntriesData v -> Index [aedEntriesSpec] :: AppendEntriesData v -> AppendEntriesSpec v -- | Representation of a message sent from a leader to its peers data AppendEntries v AppendEntries :: Term -> LeaderId -> Index -> Term -> Entries v -> Index -> Maybe Int -> AppendEntries v -- | Leader's term [aeTerm] :: AppendEntries v -> Term -- | Leader's identifier so that followers can redirect clients [aeLeaderId] :: AppendEntries v -> LeaderId -- | Index of log entry immediately preceding new ones [aePrevLogIndex] :: AppendEntries v -> Index -- | Term of aePrevLogIndex entry [aePrevLogTerm] :: AppendEntries v -> Term -- | Log entries to store (empty for heartbeat) [aeEntries] :: AppendEntries v -> Entries v -- | Leader's commit index [aeLeaderCommit] :: AppendEntries v -> Index -- | which read request the message corresponds to [aeReadRequest] :: AppendEntries v -> Maybe Int -- | Representation of the response from a follower to an AppendEntries -- message data AppendEntriesResponse AppendEntriesResponse :: Term -> Bool -> Maybe Int -> AppendEntriesResponse -- | current term for leader to update itself [aerTerm] :: AppendEntriesResponse -> Term -- | true if follower contained entry matching aePrevLogIndex and -- aePrevLogTerm [aerSuccess] :: AppendEntriesResponse -> Bool -- | which read request the response corresponds to [aerReadRequest] :: AppendEntriesResponse -> Maybe Int -- | Representation of the message sent by candidates to their peers to -- request their vote data RequestVote RequestVote :: Term -> NodeId -> Index -> Term -> RequestVote -- | candidates term [rvTerm] :: RequestVote -> Term -- | candidate requesting vote [rvCandidateId] :: RequestVote -> NodeId -- | index of candidate's last log entry [rvLastLogIndex] :: RequestVote -> Index -- | term of candidate's last log entry [rvLastLogTerm] :: RequestVote -> Term -- | Representation of a response to a RequestVote message data RequestVoteResponse RequestVoteResponse :: Term -> Bool -> RequestVoteResponse -- | current term for candidate to update itself [rvrTerm] :: RequestVoteResponse -> Term -- | true means candidate recieved vote [rvrVoteGranted] :: RequestVoteResponse -> Bool instance Data.Serialize.Serialize v => Data.Serialize.Serialize (Raft.RPC.RPCMessage v) instance GHC.Generics.Generic (Raft.RPC.RPCMessage v) instance GHC.Show.Show v => GHC.Show.Show (Raft.RPC.RPCMessage v) instance Data.Serialize.Serialize v => Data.Serialize.Serialize (Raft.RPC.RPC v) instance GHC.Generics.Generic (Raft.RPC.RPC v) instance GHC.Show.Show v => GHC.Show.Show (Raft.RPC.RPC v) instance Data.Serialize.Serialize Raft.RPC.RequestVoteResponse instance GHC.Generics.Generic Raft.RPC.RequestVoteResponse instance GHC.Show.Show Raft.RPC.RequestVoteResponse instance Data.Serialize.Serialize Raft.RPC.RequestVote instance GHC.Generics.Generic Raft.RPC.RequestVote instance GHC.Show.Show Raft.RPC.RequestVote instance Data.Serialize.Serialize Raft.RPC.AppendEntriesResponse instance GHC.Generics.Generic Raft.RPC.AppendEntriesResponse instance GHC.Show.Show Raft.RPC.AppendEntriesResponse instance Data.Serialize.Serialize v => Data.Serialize.Serialize (Raft.RPC.AppendEntries v) instance GHC.Generics.Generic (Raft.RPC.AppendEntries v) instance GHC.Show.Show v => GHC.Show.Show (Raft.RPC.AppendEntries v) instance GHC.Show.Show v => GHC.Show.Show (Raft.RPC.AppendEntriesData v) instance GHC.Show.Show v => GHC.Show.Show (Raft.RPC.AppendEntriesSpec v) instance GHC.Show.Show Raft.RPC.NoEntriesSpec instance Raft.RPC.RPCType (Raft.RPC.AppendEntries v) v instance Raft.RPC.RPCType Raft.RPC.AppendEntriesResponse v instance Raft.RPC.RPCType Raft.RPC.RequestVote v instance Raft.RPC.RPCType Raft.RPC.RequestVoteResponse v module Raft.Metrics data RaftNodeMetrics RaftNodeMetrics :: Int64 -> Int64 -> [Char] -> [Char] -> Int64 -> Int64 -> RaftNodeMetrics [invalidCmdCounter] :: RaftNodeMetrics -> Int64 [eventsHandledCounter] :: RaftNodeMetrics -> Int64 [nodeStateLabel] :: RaftNodeMetrics -> [Char] -- | Base 16 encoded last log entry hash [lastLogHashLabel] :: RaftNodeMetrics -> [Char] [lastLogIndexGauge] :: RaftNodeMetrics -> Int64 [commitIndexGauge] :: RaftNodeMetrics -> Int64 defaultRaftNodeMetrics :: RaftNodeMetrics getMetricsStore :: (MonadIO m, MonadMetrics m) => m Store getRaftNodeMetrics :: (MonadIO m, MonadMetrics m) => m RaftNodeMetrics setNodeStateLabel :: (MonadIO m, MonadMetrics m) => Mode -> m () setLastLogEntryIndexGauge :: (MonadIO m, MonadMetrics m) => Index -> m () setLastLogEntryHashLabel :: (MonadIO m, MonadMetrics m, Serialize v) => LastLogEntry v -> m () setCommitIndexGauge :: (MonadIO m, MonadMetrics m) => Index -> m () incrInvalidCmdCounter :: (MonadIO m, MonadMetrics m) => m () incrEventsHandledCounter :: (MonadIO m, MonadMetrics m) => m () instance GHC.Show.Show Raft.Metrics.RaftNodeCounter instance GHC.Show.Show Raft.Metrics.RaftNodeGauge instance GHC.Show.Show Raft.Metrics.RaftNodeLabel instance Data.Serialize.Serialize Raft.Metrics.RaftNodeMetrics instance GHC.Generics.Generic Raft.Metrics.RaftNodeMetrics instance GHC.Show.Show Raft.Metrics.RaftNodeMetrics module Raft.Config -- | Configuration of a node in the cluster data RaftNodeConfig RaftNodeConfig :: NodeId -> NodeIds -> (Natural, Natural) -> Natural -> StorageState -> RaftNodeConfig -- | Node id of the running node [raftConfigNodeId] :: RaftNodeConfig -> NodeId -- | Set of all other node ids in the cluster [raftConfigNodeIds] :: RaftNodeConfig -> NodeIds -- | Range of times an election timeout can take [raftConfigElectionTimeout] :: RaftNodeConfig -> (Natural, Natural) -- | Heartbeat timeout timer [raftConfigHeartbeatTimeout] :: RaftNodeConfig -> Natural -- | Create a fresh DB or read from existing [raftConfigStorageState] :: RaftNodeConfig -> StorageState data StorageState New :: StorageState Existing :: StorageState data OptionalRaftNodeConfig OptionalRaftNodeConfig :: Maybe PortNumber -> Maybe Int -> OptionalRaftNodeConfig [raftConfigMetricsPort] :: OptionalRaftNodeConfig -> Maybe PortNumber [raftConfigTimerSeed] :: OptionalRaftNodeConfig -> Maybe Int defaultOptionalRaftNodeConfig :: OptionalRaftNodeConfig data ConfigError InvalidMetricsPort :: ConfigError NoFreePortAvailable :: ConfigError resolveMetricsPort :: Maybe PortNumber -> IO (Maybe PortNumber) -- | If the user specifies a port to fork the EKG server on, make sure the -- port is open and return the valid port number. If the user does not -- specify a port to run the monitoring server on, return Nothing. resolveMetricsPortE :: PortNumber -> IO (Either ConfigError PortNumber) resolveTimerSeed :: Maybe Int -> IO Int instance GHC.Show.Show Raft.Config.ConfigError instance GHC.Show.Show Raft.Config.OptionalRaftNodeConfig instance GHC.Show.Show Raft.Config.RaftNodeConfig instance GHC.Show.Show Raft.Config.StorageState module Raft.Client -- | Interface for Raft nodes to send messages to clients class RaftStateMachinePure sm v => RaftSendClient m sm v sendClient :: RaftSendClient m sm v => ClientId -> ClientResponse sm v -> m () -- | Interface for Raft nodes to receive messages from clients class Show (RaftRecvClientError m v) => RaftRecvClient m v where { type family RaftRecvClientError m v; } receiveClient :: RaftRecvClient m v => m (Either (RaftRecvClientError m v) (ClientRequest v)) newtype SerialNum SerialNum :: Natural -> SerialNum -- | Representation of a client request coupled with the client id data ClientRequest v ClientRequest :: ClientId -> ClientReq v -> ClientRequest v -- | Representation of a client request data ClientReq v -- | Request the latest state of the state machine ClientReadReq :: ClientReadReq -> ClientReq v -- | Write a command ClientWriteReq :: ClientWriteReq v -> ClientReq v -- | Request the metrics of a raft node ClientMetricsReq :: ClientMetricsReq -> ClientReq v -- | Typeclass to make it easier to write polymorphic functions over -- ClientReq types class ClientReqType a v data ClientReadReq ClientReadEntries :: ReadEntriesSpec -> ClientReadReq ClientReadStateMachine :: ClientReadReq data ReadEntriesSpec data ClientWriteReq v -- | Issue a command to update the state machine ClientCmdReq :: SerialNum -> v -> ClientWriteReq v data ClientMetricsReq ClientAllMetricsReq :: ClientMetricsReq -- | The datatype sent back to the client as an actual response data ClientResponse sm v -- | Respond with the latest state of the state machine. ClientReadResponse :: ClientReadResp sm v -> ClientResponse sm v -- | Respond with the index of the entry appended to the log ClientWriteResponse :: ClientWriteResp sm v -> ClientResponse sm v -- | Respond with the node id of the current leader ClientRedirectResponse :: ClientRedirResp -> ClientResponse sm v -- | Respond with the node's current metrics ClientMetricsResponse :: ClientMetricsResp -> ClientResponse sm v -- | Specification for the data inside a ClientResponse data ClientRespSpec sm v ClientReadRespSpec :: ClientReadRespSpec sm -> ClientRespSpec sm v ClientWriteRespSpec :: ClientWriteRespSpec sm v -> ClientRespSpec sm v ClientRedirRespSpec :: CurrentLeader -> ClientRespSpec sm v ClientMetricsRespSpec :: RaftNodeMetrics -> ClientRespSpec sm v data ClientReadRespSpec sm ClientReadRespSpecEntries :: ReadEntriesSpec -> ClientReadRespSpec sm ClientReadRespSpecStateMachine :: sm -> ClientReadRespSpec sm data ClientWriteRespSpec sm v ClientWriteRespSpecSuccess :: Index -> SerialNum -> ClientWriteRespSpec sm v ClientWriteRespSpecFail :: SerialNum -> RaftStateMachinePureError sm v -> ClientWriteRespSpec sm v -- | Representation of a read response to a client data ClientReadResp sm v ClientReadRespStateMachine :: sm -> ClientReadResp sm v ClientReadRespEntry :: Entry v -> ClientReadResp sm v ClientReadRespEntries :: Entries v -> ClientReadResp sm v -- | Representation of a write response to a client data ClientWriteResp sm v -- | Index of the entry appended to the log due to the previous client -- request ClientWriteRespSuccess :: Index -> SerialNum -> ClientWriteResp sm v ClientWriteRespFail :: SerialNum -> RaftStateMachinePureError sm v -> ClientWriteResp sm v -- | Representation of a redirect response to a client data ClientRedirResp ClientRedirResp :: CurrentLeader -> ClientRedirResp data ClientMetricsResp ClientMetricsResp :: RaftNodeMetrics -> ClientMetricsResp class Monad m => RaftClientSend m v where { type family RaftClientSendError m v; } raftClientSend :: RaftClientSend m v => NodeId -> ClientRequest v -> m (Either (RaftClientSendError m v) ()) class Monad m => RaftClientRecv m sm v | m sm -> v where { type family RaftClientRecvError m sm; } raftClientRecv :: RaftClientRecv m sm v => m (Either (RaftClientRecvError m sm) (ClientResponse sm v)) -- | Each client may have at most one command outstanding at a time and -- commands must be dispatched in serial number order. data RaftClientState RaftClientState :: CurrentLeader -> SerialNum -> Set NodeId -> StdGen -> RaftClientState [raftClientCurrentLeader] :: RaftClientState -> CurrentLeader [raftClientSerialNum] :: RaftClientState -> SerialNum [raftClientRaftNodes] :: RaftClientState -> Set NodeId [raftClientRandomGen] :: RaftClientState -> StdGen data RaftClientEnv RaftClientEnv :: ClientId -> RaftClientEnv [raftClientId] :: RaftClientEnv -> ClientId initRaftClientState :: Set NodeId -> StdGen -> RaftClientState data RaftClientT s v m a runRaftClientT :: Monad m => RaftClientEnv -> RaftClientState -> RaftClientT s v m a -> m a data RaftClientError s v m [RaftClientSendError] :: RaftClientSendError m v -> RaftClientError s v m [RaftClientRecvError] :: RaftClientRecvError m s -> RaftClientError s v m [RaftClientTimeout] :: Text -> RaftClientError s v m [RaftClientUnexpectedReadResp] :: ClientReadResp s v -> RaftClientError s v m [RaftClientUnexpectedWriteResp] :: ClientWriteResp s v -> RaftClientError s v m [RaftClientUnexpectedMetricsResp] :: ClientMetricsResp -> RaftClientError s v m [RaftClientUnexpectedRedirect] :: ClientRedirResp -> RaftClientError s v m -- | Send a read request to the curent leader and wait for a response clientRead :: (RaftClientSend m v, RaftClientRecv m s v) => ClientReadReq -> RaftClientT s v m (Either (RaftClientError s v m) (ClientReadResp s v)) -- | Send a read request to a specific raft node, regardless of leader, and -- wait for a response. clientReadFrom :: (RaftClientSend m v, RaftClientRecv m s v) => NodeId -> ClientReadReq -> RaftClientT s v m (Either (RaftClientError s v m) (ClientReadResp s v)) -- | clientRead but with a timeout clientReadTimeout :: (MonadBaseControl IO m, RaftClientSend m v, RaftClientRecv m s v) => Int -> ClientReadReq -> RaftClientT s v m (Either (RaftClientError s v m) (ClientReadResp s v)) -- | Send a write request to the current leader and wait for a response clientWrite :: (RaftClientSend m v, RaftClientRecv m s v) => v -> RaftClientT s v m (Either (RaftClientError s v m) (ClientWriteResp s v)) -- | Send a read request to a specific raft node, regardless of leader, and -- wait for a response. clientWriteTo :: (RaftClientSend m v, RaftClientRecv m s v) => NodeId -> v -> RaftClientT s v m (Either (RaftClientError s v m) (ClientWriteResp s v)) clientWriteTimeout :: (MonadBaseControl IO m, RaftClientSend m v, RaftClientRecv m s v) => Int -> v -> RaftClientT s v m (Either (RaftClientError s v m) (ClientWriteResp s v)) clientQueryNodeMetrics :: (MonadBaseControl IO m, RaftClientSend m v, RaftClientRecv m s v) => NodeId -> RaftClientT s v m (Either (RaftClientError s v m) ClientMetricsResp) clientQueryNodeMetricsTimeout :: (MonadBaseControl IO m, RaftClientSend m v, RaftClientRecv m s v) => Int -> NodeId -> RaftClientT s v m (Either (RaftClientError s v m) ClientMetricsResp) -- | Send a read request to the current leader. Nonblocking. clientSendRead :: RaftClientSend m v => ClientReadReq -> RaftClientT s v m (Either (RaftClientSendError m v) ()) -- | Send a write request to the current leader. Nonblocking. clientSendWrite :: RaftClientSend m v => v -> RaftClientT s v m (Either (RaftClientSendError m v) ()) clientSendMetricsReqTo :: RaftClientSend m v => NodeId -> RaftClientT s v m (Either (RaftClientSendError m v) ()) -- | Send a request to the current leader. Nonblocking. clientSend :: RaftClientSend m v => ClientReq v -> RaftClientT s v m (Either (RaftClientSendError m v) ()) -- | Wait for a response from the current leader. This function handles -- leader changes and write request serial numbers. clientRecv :: RaftClientRecv m s v => RaftClientT s v m (Either (RaftClientRecvError m s) (ClientResponse s v)) clientTimeout :: (MonadBaseControl IO m, RaftClientSend m v, RaftClientRecv m s v) => Text -> Int -> RaftClientT s v m (Either (RaftClientError s v m) r) -> RaftClientT s v m (Either (RaftClientError s v m) r) -- | Given a blocking client send/receive, retry if the received value is -- not expected retryOnRedirect :: MonadBaseControl IO m => RaftClientT s v m (Either (RaftClientError s v m) r) -> RaftClientT s v m (Either (RaftClientError s v m) r) clientAddNode :: Monad m => NodeId -> RaftClientT s v m () clientGetNodes :: Monad m => RaftClientT s v m (Set NodeId) instance GHC.Base.MonadPlus m => GHC.Base.MonadPlus (Raft.Client.RaftClientT s v m) instance GHC.Base.MonadPlus m => GHC.Base.Alternative (Raft.Client.RaftClientT s v m) instance Control.Monad.Fail.MonadFail m => Control.Monad.Fail.MonadFail (Raft.Client.RaftClientT s v m) instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader Raft.Client.RaftClientEnv (Raft.Client.RaftClientT s v m) instance GHC.Base.Monad m => Control.Monad.State.Class.MonadState Raft.Client.RaftClientState (Raft.Client.RaftClientT s v m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Raft.Client.RaftClientT s v m) instance GHC.Base.Monad m => GHC.Base.Monad (Raft.Client.RaftClientT s v m) instance GHC.Base.Monad m => GHC.Base.Applicative (Raft.Client.RaftClientT s v m) instance GHC.Base.Functor m => GHC.Base.Functor (Raft.Client.RaftClientT s v m) instance GHC.Generics.Generic (Raft.Client.ClientResponse sm v) instance Data.Serialize.Serialize Raft.Client.ClientMetricsResp instance GHC.Generics.Generic Raft.Client.ClientMetricsResp instance GHC.Show.Show Raft.Client.ClientMetricsResp instance Data.Serialize.Serialize Raft.Client.ClientRedirResp instance GHC.Generics.Generic Raft.Client.ClientRedirResp instance GHC.Show.Show Raft.Client.ClientRedirResp instance GHC.Generics.Generic (Raft.Client.ClientWriteResp sm v) instance (Data.Serialize.Serialize sm, Data.Serialize.Serialize v) => Data.Serialize.Serialize (Raft.Client.ClientReadResp sm v) instance GHC.Generics.Generic (Raft.Client.ClientReadResp sm v) instance (GHC.Show.Show sm, GHC.Show.Show v) => GHC.Show.Show (Raft.Client.ClientReadResp sm v) instance GHC.Generics.Generic (Raft.Client.ClientRespSpec sm v) instance GHC.Generics.Generic (Raft.Client.ClientWriteRespSpec sm v) instance Data.Serialize.Serialize sm => Data.Serialize.Serialize (Raft.Client.ClientReadRespSpec sm) instance GHC.Generics.Generic (Raft.Client.ClientReadRespSpec sm) instance GHC.Show.Show sm => GHC.Show.Show (Raft.Client.ClientReadRespSpec sm) instance GHC.Generics.Generic (Raft.Client.ClientRequest v) instance GHC.Show.Show v => GHC.Show.Show (Raft.Client.ClientRequest v) instance GHC.Generics.Generic (Raft.Client.ClientReq v) instance GHC.Show.Show v => GHC.Show.Show (Raft.Client.ClientReq v) instance Data.Serialize.Serialize Raft.Client.ClientMetricsReq instance GHC.Generics.Generic Raft.Client.ClientMetricsReq instance GHC.Show.Show Raft.Client.ClientMetricsReq instance Data.Serialize.Serialize v => Data.Serialize.Serialize (Raft.Client.ClientWriteReq v) instance GHC.Generics.Generic (Raft.Client.ClientWriteReq v) instance GHC.Show.Show v => GHC.Show.Show (Raft.Client.ClientWriteReq v) instance Data.Serialize.Serialize Raft.Client.ClientReadReq instance GHC.Generics.Generic Raft.Client.ClientReadReq instance GHC.Show.Show Raft.Client.ClientReadReq instance (GHC.Show.Show sm, GHC.Show.Show v, GHC.Show.Show (Raft.StateMachine.RaftStateMachinePureError sm v)) => GHC.Show.Show (Raft.Client.ClientRespSpec sm v) instance (Data.Serialize.Serialize sm, Data.Serialize.Serialize v, Data.Serialize.Serialize (Raft.StateMachine.RaftStateMachinePureError sm v)) => Data.Serialize.Serialize (Raft.Client.ClientRespSpec sm v) instance (GHC.Show.Show sm, GHC.Show.Show v, GHC.Show.Show (Raft.StateMachine.RaftStateMachinePureError sm v)) => GHC.Show.Show (Raft.Client.ClientWriteRespSpec sm v) instance (Data.Serialize.Serialize sm, Data.Serialize.Serialize v, Data.Serialize.Serialize (Raft.StateMachine.RaftStateMachinePureError sm v)) => Data.Serialize.Serialize (Raft.Client.ClientWriteRespSpec sm v) instance (GHC.Show.Show sm, GHC.Show.Show v, GHC.Show.Show (Raft.Client.ClientWriteResp sm v)) => GHC.Show.Show (Raft.Client.ClientResponse sm v) instance (Data.Serialize.Serialize sm, Data.Serialize.Serialize v, Data.Serialize.Serialize (Raft.Client.ClientWriteResp sm v)) => Data.Serialize.Serialize (Raft.Client.ClientResponse sm v) instance (GHC.Show.Show sm, GHC.Show.Show v, GHC.Show.Show (Raft.StateMachine.RaftStateMachinePureError sm v)) => GHC.Show.Show (Raft.Client.ClientWriteResp sm v) instance (Data.Serialize.Serialize sm, Data.Serialize.Serialize v, Data.Serialize.Serialize (Raft.StateMachine.RaftStateMachinePureError sm v)) => Data.Serialize.Serialize (Raft.Client.ClientWriteResp sm v) instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Raft.Client.RaftClientT s v m) instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Raft.Client.RaftClientT s v m) instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Raft.Client.RaftClientT s v m) instance Control.Monad.Base.MonadBase GHC.Types.IO m => Control.Monad.Base.MonadBase GHC.Types.IO (Raft.Client.RaftClientT s v m) instance (GHC.Show.Show s, GHC.Show.Show v, GHC.Show.Show (Raft.Client.RaftClientSendError m v), GHC.Show.Show (Raft.Client.RaftClientRecvError m s), GHC.Show.Show (Raft.StateMachine.RaftStateMachinePureError s v)) => GHC.Show.Show (Raft.Client.RaftClientError s v m) instance Control.Monad.Trans.Class.MonadTrans (Raft.Client.RaftClientT s v) instance Control.Monad.Trans.Control.MonadTransControl (Raft.Client.RaftClientT s v) instance Control.Monad.Trans.Control.MonadBaseControl GHC.Types.IO m => Control.Monad.Trans.Control.MonadBaseControl GHC.Types.IO (Raft.Client.RaftClientT s v m) instance System.Console.Haskeline.MonadException.MonadException m => System.Console.Haskeline.MonadException.MonadException (Raft.Client.RaftClientT s v m) instance Raft.Client.RaftClientSend m v => Raft.Client.RaftClientSend (Raft.Client.RaftClientT s v m) v instance Raft.Client.RaftClientRecv m s v => Raft.Client.RaftClientRecv (Raft.Client.RaftClientT s v m) s v instance Raft.Client.ClientReqType Raft.Client.ClientReadReq v instance Raft.Client.ClientReqType (Raft.Client.ClientWriteReq v) v instance Raft.Client.ClientReqType Raft.Client.ClientMetricsReq v instance Data.Serialize.Serialize v => Data.Serialize.Serialize (Raft.Client.ClientRequest v) instance Data.Serialize.Serialize v => Data.Serialize.Serialize (Raft.Client.ClientReq v) module Raft.NodeState -- | All valid state transitions of a Raft node data Transition (init :: Mode) (res :: Mode) [StartElection] :: Transition 'Follower 'Candidate [HigherTermFoundFollower] :: Transition 'Follower 'Follower [RestartElection] :: Transition 'Candidate 'Candidate [DiscoverLeader] :: Transition 'Candidate 'Follower [HigherTermFoundCandidate] :: Transition 'Candidate 'Follower [BecomeLeader] :: Transition 'Candidate 'Leader [HandleClientReq] :: Transition 'Leader 'Leader [SendHeartbeat] :: Transition 'Leader 'Leader [DiscoverNewLeader] :: Transition 'Leader 'Follower [HigherTermFoundLeader] :: Transition 'Leader 'Follower [Noop] :: Transition init init -- | Existential type hiding the result type of a transition data ResultState init v [ResultState] :: Show v => Transition init res -> NodeState res v -> ResultState init v followerResultState :: Show v => Transition init 'Follower -> FollowerState v -> ResultState init v candidateResultState :: Show v => Transition init 'Candidate -> CandidateState v -> ResultState init v leaderResultState :: Show v => Transition init 'Leader -> LeaderState v -> ResultState init v -- | Existential type hiding the internal node state data RaftNodeState v [RaftNodeState] :: {unRaftNodeState :: NodeState s v} -> RaftNodeState v nodeMode :: RaftNodeState v -> Mode -- | A node in Raft begins as a follower initRaftNodeState :: RaftNodeState v -- | The volatile state of a Raft Node data NodeState (a :: Mode) v [NodeFollowerState] :: FollowerState v -> NodeState 'Follower v [NodeCandidateState] :: CandidateState v -> NodeState 'Candidate v [NodeLeaderState] :: LeaderState v -> NodeState 'Leader v data FollowerState v FollowerState :: CurrentLeader -> Index -> Index -> LastLogEntry v -> Maybe Term -> ClientWriteReqCache -> FollowerState v -- | Id of the current leader [fsCurrentLeader] :: FollowerState v -> CurrentLeader -- | Index of highest log entry known to be committed [fsCommitIndex] :: FollowerState v -> Index -- | Index of highest log entry applied to state machine [fsLastApplied] :: FollowerState v -> Index -- | Index and term of the last log entry in the node's log [fsLastLogEntry] :: FollowerState v -> LastLogEntry v -- | The term of the log entry specified in and AppendEntriesRPC [fsTermAtAEPrevIndex] :: FollowerState v -> Maybe Term -- | The client write request cache, growing linearly with the number of -- clients [fsClientReqCache] :: FollowerState v -> ClientWriteReqCache data CandidateState v CandidateState :: Index -> Index -> NodeIds -> LastLogEntry v -> ClientWriteReqCache -> CandidateState v -- | Index of highest log entry known to be committed [csCommitIndex] :: CandidateState v -> Index -- | Index of highest log entry applied to state machine [csLastApplied] :: CandidateState v -> Index -- | Votes from other nodes in the raft network [csVotes] :: CandidateState v -> NodeIds -- | Index and term of the last log entry in the node's log [csLastLogEntry] :: CandidateState v -> LastLogEntry v -- | The client write request cache, growing linearly with the number of -- clients [csClientReqCache] :: CandidateState v -> ClientWriteReqCache data ClientReadReqData ClientReadReqData :: ClientId -> ClientReadReq -> ClientReadReqData [crrdClientId] :: ClientReadReqData -> ClientId [crrdReadReq] :: ClientReadReqData -> ClientReadReq -- | The type mapping the number of the read request serviced to the id of -- the client that issued it and the number of success responses from -- followers confirming the leadership of the current leader type ClientReadReqs = Map Int (ClientReadReqData, Int) -- | The type mapping client ids to the serial number of their latest write -- requests and the index of the entry if it has been replicated. type ClientWriteReqCache = Map ClientId (SerialNum, Maybe Index) data LeaderState v LeaderState :: Index -> Index -> Map NodeId Index -> Map NodeId Index -> LastLogEntry v -> Int -> ClientReadReqs -> ClientWriteReqCache -> LeaderState v -- | Index of highest log entry known to be committed [lsCommitIndex] :: LeaderState v -> Index -- | Index of highest log entry applied to state machine [lsLastApplied] :: LeaderState v -> Index -- | For each server, index of the next log entry to send to that server [lsNextIndex] :: LeaderState v -> Map NodeId Index -- | For each server, index of highest log entry known to be replicated on -- server [lsMatchIndex] :: LeaderState v -> Map NodeId Index -- | Index, term, and client id of the last log entry in the node's log. -- The only time `Maybe ClientId` will be Nothing is at the initial term. [lsLastLogEntry] :: LeaderState v -> LastLogEntry v -- | Number of read requests handled this term [lsReadReqsHandled] :: LeaderState v -> Int -- | The number of successful responses received regarding a specific read -- request heartbeat. [lsReadRequest] :: LeaderState v -> ClientReadReqs -- | The cache of client write requests received by the leader [lsClientReqCache] :: LeaderState v -> ClientWriteReqCache -- | Update the last log entry in the node's log setLastLogEntry :: NodeState s v -> Entries v -> NodeState s v -- | Get the last applied index and the commit index of the last log entry -- in the node's log getLastLogEntry :: NodeState ns v -> LastLogEntry v getLastLogEntryIndex :: NodeState ns v -> Index getCommitIndex :: NodeState ns v -> Index -- | Get the index of highest log entry applied to state machine and the -- index of highest log entry known to be committed getLastAppliedAndCommitIndex :: NodeState ns v -> (Index, Index) -- | Check if node is in a follower state isFollower :: NodeState s v -> Bool -- | Check if node is in a candidate state isCandidate :: NodeState s v -> Bool -- | Check if node is in a leader state isLeader :: NodeState s v -> Bool instance GHC.Show.Show v => GHC.Show.Show (Raft.NodeState.LeaderState v) instance GHC.Show.Show v => GHC.Show.Show (Raft.NodeState.FollowerState v) instance GHC.Show.Show v => GHC.Show.Show (Raft.NodeState.CandidateState v) instance GHC.Show.Show Raft.NodeState.ClientReadReqData instance GHC.Show.Show (Raft.NodeState.Transition init res) instance GHC.Show.Show v => GHC.Show.Show (Raft.NodeState.ResultState init v) instance GHC.Show.Show v => GHC.Show.Show (Raft.NodeState.RaftNodeState v) instance GHC.Show.Show v => GHC.Show.Show (Raft.NodeState.NodeState s v) module Raft.Logging -- | Representation of the logs' context data LogCtx m LogCtx :: LogDest m -> Severity -> LogCtx m [logCtxDest] :: LogCtx m -> LogDest m [logCtxSeverity] :: LogCtx m -> Severity NoLogs :: LogCtx m -- | Representation of the logs' destination data LogDest m LogWith :: (MonadIO m => Severity -> Text -> m ()) -> LogDest m LogFile :: FilePath -> LogDest m LogStdout :: LogDest m -- | Representation of the severity of the logs data Severity Debug :: Severity Info :: Severity Critical :: Severity data LogMsg LogMsg :: Maybe SystemTime -> Severity -> LogMsgData -> LogMsg [mTime] :: LogMsg -> Maybe SystemTime [severity] :: LogMsg -> Severity [logMsgData] :: LogMsg -> LogMsgData data LogMsgData LogMsgData :: NodeId -> Mode -> Text -> LogMsgData [logMsgNodeId] :: LogMsgData -> NodeId [logMsgNodeState] :: LogMsgData -> Mode [logMsg] :: LogMsgData -> Text logMsgToText :: LogMsg -> Text logMsgDataToText :: LogMsgData -> Text class Monad m => RaftLogger v m | m -> v loggerCtx :: RaftLogger v m => m (NodeId, RaftNodeState v) mkLogMsgData :: RaftLogger v m => Text -> m LogMsgData logToDest :: MonadIO m => LogCtx m -> LogMsg -> m () logToStdout :: MonadIO m => Severity -> LogMsg -> m () logToFile :: MonadIO m => FilePath -> Severity -> LogMsg -> m () logWithSeverityIO :: forall m v. (RaftLogger v m, MonadIO m) => Severity -> LogCtx m -> Text -> m () logInfoIO :: (RaftLogger v m, MonadIO m) => LogCtx m -> Text -> m () logDebugIO :: (RaftLogger v m, MonadIO m) => LogCtx m -> Text -> m () logCriticalIO :: (RaftLogger v m, MonadIO m) => LogCtx m -> Text -> m () newtype RaftLoggerT v m a RaftLoggerT :: StateT [LogMsg] m a -> RaftLoggerT v m a [unRaftLoggerT] :: RaftLoggerT v m a -> StateT [LogMsg] m a runRaftLoggerT :: Monad m => RaftLoggerT v m a -> m (a, [LogMsg]) type RaftLoggerM v = RaftLoggerT v Identity runRaftLoggerM :: RaftLoggerM v a -> (a, [LogMsg]) logWithSeverity :: RaftLogger v m => Severity -> Text -> RaftLoggerT v m () logInfo :: RaftLogger v m => Text -> RaftLoggerT v m () logDebug :: RaftLogger v m => Text -> RaftLoggerT v m () logCritical :: RaftLogger v m => Text -> RaftLoggerT v m () logAndPanic :: RaftLogger v m => Text -> m a logAndPanicIO :: (RaftLogger v m, MonadIO m) => LogCtx m -> Text -> m a instance Control.Monad.Trans.Class.MonadTrans (Raft.Logging.RaftLoggerT v) instance GHC.Base.Monad m => Control.Monad.State.Class.MonadState [Raft.Logging.LogMsg] (Raft.Logging.RaftLoggerT v m) instance GHC.Base.Monad m => GHC.Base.Monad (Raft.Logging.RaftLoggerT v m) instance GHC.Base.Monad m => GHC.Base.Applicative (Raft.Logging.RaftLoggerT v m) instance GHC.Base.Functor m => GHC.Base.Functor (Raft.Logging.RaftLoggerT v m) instance GHC.Show.Show Raft.Logging.LogMsg instance GHC.Show.Show Raft.Logging.LogMsgData instance GHC.Classes.Ord Raft.Logging.Severity instance GHC.Classes.Eq Raft.Logging.Severity instance GHC.Show.Show Raft.Logging.Severity instance Raft.Logging.RaftLogger v m => Raft.Logging.RaftLogger v (Raft.Logging.RaftLoggerT v m) module Raft.Event -- | Representation of events a raft node can send and receive data Event v MessageEvent :: MessageEvent v -> Event v TimeoutEvent :: SystemTime -> Timeout -> Event v -- | Representation of timeouts data Timeout -- | Timeout after which a follower will become candidate ElectionTimeout :: Timeout -- | Timeout after which a leader will send AppendEntries RPC to all peers HeartbeatTimeout :: Timeout -- | Representation of message events to a node data MessageEvent v -- | Incoming event from a peer RPCMessageEvent :: RPCMessage v -> MessageEvent v -- | Incoming event from a client ClientRequestEvent :: ClientRequest v -> MessageEvent v instance GHC.Show.Show v => GHC.Show.Show (Raft.Event.Event v) instance GHC.Generics.Generic (Raft.Event.MessageEvent v) instance GHC.Show.Show v => GHC.Show.Show (Raft.Event.MessageEvent v) instance GHC.Show.Show Raft.Event.Timeout instance Data.Serialize.Serialize v => Data.Serialize.Serialize (Raft.Event.MessageEvent v) module Raft.Monad type MonadRaft v m = (MonadRaftChan v m, MonadRaftFork m) -- | The typeclass specifying the datatype used as the core event channel -- in the main raft event loop, as well as functions for creating, -- reading, and writing to the channel, and how to fork a computation -- that performs some action with the channel. -- -- Note: This module uses AllowAmbiguousTypes which removes the necessity -- for Proxy value arguments in lieu of TypeApplication. For example: -- --
-- newRaftChan @v ---- -- instead of -- --
-- newRaftChan (Proxy :: Proxy v) --class Monad m => MonadRaftChan v m where { type family RaftEventChan v m; } readRaftChan :: MonadRaftChan v m => RaftEventChan v m -> m (Event v) writeRaftChan :: MonadRaftChan v m => RaftEventChan v m -> Event v -> m () newRaftChan :: MonadRaftChan v m => m (RaftEventChan v m) data RaftThreadRole RPCHandler :: RaftThreadRole ClientRequestHandler :: RaftThreadRole CustomThreadRole :: Text -> RaftThreadRole -- | The typeclass encapsulating the concurrency operations necessary for -- the implementation of the main event handling loop. class Monad m => MonadRaftFork m where { type family RaftThreadId m; } raftFork :: MonadRaftFork m => RaftThreadRole -> m () -> m (RaftThreadId m) -- | The raft server environment composed of the concurrent variables used -- in the effectful raft layer. data RaftEnv v m RaftEnv :: RaftEventChan v m -> m () -> m () -> RaftNodeConfig -> LogCtx (RaftT v m) -> Metrics -> RaftEnv v m [eventChan] :: RaftEnv v m -> RaftEventChan v m [resetElectionTimer] :: RaftEnv v m -> m () [resetHeartbeatTimer] :: RaftEnv v m -> m () [raftNodeConfig] :: RaftEnv v m -> RaftNodeConfig [raftNodeLogCtx] :: RaftEnv v m -> LogCtx (RaftT v m) [raftNodeMetrics] :: RaftEnv v m -> Metrics initializeRaftEnv :: MonadIO m => RaftEventChan v m -> m () -> m () -> RaftNodeConfig -> LogCtx (RaftT v m) -> m (RaftEnv v m) data RaftT v m a runRaftT :: Monad m => RaftNodeState v -> RaftEnv v m -> RaftT v m a -> m a logInfo :: MonadIO m => Text -> RaftT v m () logDebug :: MonadIO m => Text -> RaftT v m () logCritical :: MonadIO m => Text -> RaftT v m () logAndPanic :: MonadIO m => Text -> RaftT v m a instance GHC.Base.MonadPlus m => GHC.Base.MonadPlus (Raft.Monad.RaftT v m) instance GHC.Base.MonadPlus m => GHC.Base.Alternative (Raft.Monad.RaftT v m) instance Control.Monad.Fail.MonadFail m => Control.Monad.Fail.MonadFail (Raft.Monad.RaftT v m) instance GHC.Base.Monad m => Control.Monad.State.Class.MonadState (Raft.NodeState.RaftNodeState v) (Raft.Monad.RaftT v m) instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (Raft.Monad.RaftEnv v m) (Raft.Monad.RaftT v m) instance GHC.Base.Monad m => GHC.Base.Monad (Raft.Monad.RaftT v m) instance GHC.Base.Monad m => GHC.Base.Applicative (Raft.Monad.RaftT v m) instance GHC.Base.Functor m => GHC.Base.Functor (Raft.Monad.RaftT v m) instance GHC.Show.Show Raft.Monad.RaftThreadRole instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Raft.Monad.RaftT v m) instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Raft.Monad.RaftT v m) instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Raft.Monad.RaftT v m) instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Raft.Monad.RaftT v m) instance Control.Monad.Trans.Class.MonadTrans (Raft.Monad.RaftT v) instance Raft.Monad.MonadRaftFork m => Raft.Monad.MonadRaftFork (Raft.Monad.RaftT v m) instance GHC.Base.Monad m => Raft.Logging.RaftLogger v (Raft.Monad.RaftT v m) instance GHC.Base.Monad m => Control.Monad.Metrics.MonadMetrics (Raft.Monad.RaftT v m) instance Raft.Monad.MonadRaftFork GHC.Types.IO instance Raft.Monad.MonadRaftFork Test.DejaFu.Conc.ConcIO instance Raft.Monad.MonadRaftChan v GHC.Types.IO instance Raft.Monad.MonadRaftChan v Test.DejaFu.Conc.ConcIO module Raft.Log.PostgreSQL -- | A single threaded PostgreSQL storage monad transformer newtype RaftPostgresT m a RaftPostgresT :: ReaderT RaftPostgresEnv m a -> RaftPostgresT m a [unRaftPostgresT] :: RaftPostgresT m a -> ReaderT RaftPostgresEnv m a -- | Run a RaftPostgresT computation by supplying the database connection -- info runRaftPostgresT :: MonadIO m => ConnectInfo -> RaftPostgresT m a -> m a runRaftPostgresM :: ConnectInfo -> RaftPostgresM a -> IO a raftDatabaseName :: [Char] -> [Char] raftDatabaseConnInfo :: [Char] -> [Char] -> [Char] -> ConnectInfo initConnInfo :: ConnectInfo -- | Create the libraft database to store all log entries setupDB :: ConnectInfo -> IO (Either PGError Connection) deleteDB :: [Char] -> Connection -> IO Int64 instance GHC.Show.Show Raft.Log.PostgreSQL.RaftPostgresError instance GHC.Show.Show Raft.Log.PostgreSQL.PGError instance (Data.Typeable.Internal.Typeable v, Data.Serialize.Serialize v) => Database.PostgreSQL.Simple.FromRow.FromRow (Raft.Log.PostgreSQL.EntryRow v) instance Data.Serialize.Serialize v => Database.PostgreSQL.Simple.ToRow.ToRow (Raft.Log.PostgreSQL.EntryRow v) instance GHC.Generics.Generic (Raft.Log.PostgreSQL.EntryRow v) instance GHC.Show.Show v => GHC.Show.Show (Raft.Log.PostgreSQL.EntryRow v) instance Control.Monad.Trans.Class.MonadTrans Raft.Log.PostgreSQL.RaftPostgresT instance GHC.Base.MonadPlus m => GHC.Base.MonadPlus (Raft.Log.PostgreSQL.RaftPostgresT m) instance GHC.Base.Alternative m => GHC.Base.Alternative (Raft.Log.PostgreSQL.RaftPostgresT m) instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader Raft.Log.PostgreSQL.RaftPostgresEnv (Raft.Log.PostgreSQL.RaftPostgresT m) instance Control.Monad.Fail.MonadFail m => Control.Monad.Fail.MonadFail (Raft.Log.PostgreSQL.RaftPostgresT m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Raft.Log.PostgreSQL.RaftPostgresT m) instance GHC.Base.Monad m => GHC.Base.Monad (Raft.Log.PostgreSQL.RaftPostgresT m) instance GHC.Base.Applicative m => GHC.Base.Applicative (Raft.Log.PostgreSQL.RaftPostgresT m) instance GHC.Base.Functor m => GHC.Base.Functor (Raft.Log.PostgreSQL.RaftPostgresT m) instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Raft.Log.PostgreSQL.RaftPostgresT m) instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Raft.Log.PostgreSQL.RaftPostgresT m) instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Raft.Log.PostgreSQL.RaftPostgresT m) instance GHC.Exception.Type.Exception Raft.Log.PostgreSQL.RaftPostgresError instance Control.Monad.IO.Class.MonadIO m => Raft.Log.RaftInitLog (Raft.Log.PostgreSQL.RaftPostgresT m) v instance (Data.Typeable.Internal.Typeable v, Data.Serialize.Serialize v, Control.Monad.IO.Class.MonadIO m) => Raft.Log.RaftReadLog (Raft.Log.PostgreSQL.RaftPostgresT m) v instance (Data.Serialize.Serialize v, Control.Monad.IO.Class.MonadIO m) => Raft.Log.RaftWriteLog (Raft.Log.PostgreSQL.RaftPostgresT m) v instance (Data.Serialize.Serialize v, Control.Monad.IO.Class.MonadIO m) => Raft.Log.RaftDeleteLog (Raft.Log.PostgreSQL.RaftPostgresT m) v instance Raft.Persistent.RaftPersist m => Raft.Persistent.RaftPersist (Raft.Log.PostgreSQL.RaftPostgresT m) instance (GHC.Base.Monad m, Raft.RPC.RaftSendRPC m v) => Raft.RPC.RaftSendRPC (Raft.Log.PostgreSQL.RaftPostgresT m) v instance (GHC.Base.Monad m, Raft.RPC.RaftRecvRPC m v) => Raft.RPC.RaftRecvRPC (Raft.Log.PostgreSQL.RaftPostgresT m) v instance (GHC.Base.Monad m, Raft.Client.RaftSendClient m sm v) => Raft.Client.RaftSendClient (Raft.Log.PostgreSQL.RaftPostgresT m) sm v instance (GHC.Base.Monad m, Raft.Client.RaftRecvClient m v) => Raft.Client.RaftRecvClient (Raft.Log.PostgreSQL.RaftPostgresT m) v instance Raft.StateMachine.RaftStateMachine m sm v => Raft.StateMachine.RaftStateMachine (Raft.Log.PostgreSQL.RaftPostgresT m) sm v instance Raft.Monad.MonadRaftChan v m => Raft.Monad.MonadRaftChan v (Raft.Log.PostgreSQL.RaftPostgresT m) instance (Control.Monad.IO.Class.MonadIO m, Raft.Monad.MonadRaftFork m) => Raft.Monad.MonadRaftFork (Raft.Log.PostgreSQL.RaftPostgresT m) module Examples.Raft.FileStore.Persistent newtype RaftPersistFileStoreError RaftPersistFileStoreError :: Text -> RaftPersistFileStoreError newtype RaftPersistFile RaftPersistFile :: FilePath -> RaftPersistFile newtype RaftPersistFileStoreT m a RaftPersistFileStoreT :: ReaderT RaftPersistFile m a -> RaftPersistFileStoreT m a [unRaftPersistFileStoreT] :: RaftPersistFileStoreT m a -> ReaderT RaftPersistFile m a runRaftPersistFileStoreT :: RaftPersistFile -> RaftPersistFileStoreT m a -> m a instance Control.Monad.Trans.Class.MonadTrans Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT instance GHC.Base.MonadPlus m => GHC.Base.MonadPlus (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance GHC.Base.Alternative m => GHC.Base.Alternative (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader Examples.Raft.FileStore.Persistent.RaftPersistFile (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance Control.Monad.Fail.MonadFail m => Control.Monad.Fail.MonadFail (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance GHC.Base.Monad m => GHC.Base.Monad (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance GHC.Base.Applicative m => GHC.Base.Applicative (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance GHC.Base.Functor m => GHC.Base.Functor (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance GHC.Show.Show Examples.Raft.FileStore.Persistent.RaftPersistFileStoreError instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance Control.Monad.IO.Class.MonadIO m => Raft.Persistent.RaftPersist (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance Raft.StateMachine.RaftStateMachine m sm v => Raft.StateMachine.RaftStateMachine (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) sm v instance (Control.Monad.IO.Class.MonadIO m, Control.Monad.Catch.MonadMask m, Raft.Client.RaftSendClient m sm v) => Raft.Client.RaftSendClient (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) sm v instance (Control.Monad.IO.Class.MonadIO m, Raft.Client.RaftRecvClient m v) => Raft.Client.RaftRecvClient (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) v instance (Control.Monad.IO.Class.MonadIO m, Control.Monad.Catch.MonadMask m, Raft.RPC.RaftSendRPC m v) => Raft.RPC.RaftSendRPC (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) v instance (Control.Monad.IO.Class.MonadIO m, Raft.RPC.RaftRecvRPC m v) => Raft.RPC.RaftRecvRPC (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) v instance (Control.Monad.IO.Class.MonadIO m, Raft.Log.RaftInitLog m v) => Raft.Log.RaftInitLog (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) v instance Raft.Log.RaftWriteLog m v => Raft.Log.RaftWriteLog (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) v instance Raft.Log.RaftReadLog m v => Raft.Log.RaftReadLog (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) v instance Raft.Log.RaftDeleteLog m v => Raft.Log.RaftDeleteLog (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) v instance Raft.Monad.MonadRaftChan v m => Raft.Monad.MonadRaftChan v (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance (Control.Monad.IO.Class.MonadIO m, Raft.Monad.MonadRaftFork m) => Raft.Monad.MonadRaftFork (Examples.Raft.FileStore.Persistent.RaftPersistFileStoreT m) instance GHC.Exception.Type.Exception Examples.Raft.FileStore.Persistent.RaftPersistFileStoreError module Raft.Action data Action sm v -- | Send a message to a specific node id SendRPC :: NodeId -> SendRPCAction v -> Action sm v -- | Send a unique message to specific nodes in parallel SendRPCs :: Map NodeId (SendRPCAction v) -> Action sm v -- | Broadcast the same message to all nodes BroadcastRPC :: NodeIds -> SendRPCAction v -> Action sm v -- | Append entries to the replicated log AppendLogEntries :: Entries v -> Action sm v -- | Respond to client after a client request RespondToClient :: ClientId -> ClientRespSpec sm v -> Action sm v -- | Reset a timeout timer ResetTimeoutTimer :: Timeout -> Action sm v -- | Update the client request cache from the given index onward UpdateClientReqCacheFrom :: Index -> Action sm v data SendRPCAction v SendAppendEntriesRPC :: AppendEntriesData v -> SendRPCAction v SendAppendEntriesResponseRPC :: AppendEntriesResponse -> SendRPCAction v SendRequestVoteRPC :: RequestVote -> SendRPCAction v SendRequestVoteResponseRPC :: RequestVoteResponse -> SendRPCAction v instance GHC.Show.Show v => GHC.Show.Show (Raft.Action.SendRPCAction v) instance (GHC.Show.Show sm, GHC.Show.Show v, GHC.Show.Show (Raft.StateMachine.RaftStateMachinePureError sm v)) => GHC.Show.Show (Raft.Action.Action sm v) module Raft.Transition tellAction :: Action sm v -> TransitionM sm v () tellActions :: [Action sm v] -> TransitionM sm v () data TransitionEnv sm v TransitionEnv :: RaftNodeConfig -> sm -> RaftNodeState v -> RaftNodeMetrics -> TransitionEnv sm v [nodeConfig] :: TransitionEnv sm v -> RaftNodeConfig [stateMachine] :: TransitionEnv sm v -> sm [nodeState] :: TransitionEnv sm v -> RaftNodeState v [nodeMetrics] :: TransitionEnv sm v -> RaftNodeMetrics newtype TransitionM sm v a TransitionM :: RaftLoggerT v (RWS (TransitionEnv sm v) [Action sm v] PersistentState) a -> TransitionM sm v a [unTransitionM] :: TransitionM sm v a -> RaftLoggerT v (RWS (TransitionEnv sm v) [Action sm v] PersistentState) a runTransitionM :: TransitionEnv sm v -> PersistentState -> TransitionM sm v a -> ((a, [LogMsg]), PersistentState, [Action sm v]) askNodeId :: TransitionM sm v NodeId -- | Returns the set of all node ids excluding the node's own id askPeerNodeIds :: TransitionM sm v NodeIds type RPCHandler ns sm r v = (RPCType r v, Show v) => NodeState ns v -> NodeId -> r -> TransitionM sm v (ResultState ns v) type TimeoutHandler ns sm v = Show v => NodeState ns v -> Timeout -> TransitionM sm v (ResultState ns v) type ClientReqHandler ns cr sm v = (ClientReqType cr v, Show v) => NodeState ns v -> ClientId -> cr -> TransitionM sm v (ResultState ns v) broadcast :: SendRPCAction v -> TransitionM sm v () send :: NodeId -> SendRPCAction v -> TransitionM sm v () -- | Resets the election timeout. resetElectionTimeout :: TransitionM sm v () resetHeartbeatTimeout :: TransitionM sm v () redirectClientToLeader :: ClientId -> CurrentLeader -> TransitionM sm v () respondClientRead :: ClientId -> ClientReadReq -> TransitionM sm v () respondClientWrite :: ClientId -> Index -> SerialNum -> TransitionM sm v () respondClientMetrics :: ClientId -> TransitionM sm v () respondClientRedir :: ClientId -> CurrentLeader -> TransitionM sm v () appendLogEntries :: Show v => Seq (Entry v) -> TransitionM sm v () updateClientReqCacheFromIdx :: Index -> TransitionM sm v () startElection :: Index -> Index -> LastLogEntry v -> ClientWriteReqCache -> TransitionM sm v (CandidateState v) logInfo :: () => Text -> TransitionM sm v () logDebug :: () => Text -> TransitionM sm v () instance GHC.Base.Monad (Raft.Transition.TransitionM sm v) instance GHC.Base.Applicative (Raft.Transition.TransitionM sm v) instance GHC.Base.Functor (Raft.Transition.TransitionM sm v) instance Control.Monad.Writer.Class.MonadWriter [Raft.Action.Action sm v] (Raft.Transition.TransitionM sm v) instance Control.Monad.Reader.Class.MonadReader (Raft.Transition.TransitionEnv sm v) (Raft.Transition.TransitionM sm v) instance Control.Monad.State.Class.MonadState Raft.Persistent.PersistentState (Raft.Transition.TransitionM sm v) instance Raft.Logging.RaftLogger v (Control.Monad.Trans.RWS.Strict.RWS (Raft.Transition.TransitionEnv sm v) [Raft.Action.Action sm v] Raft.Persistent.PersistentState) module Raft.Leader -- | Leaders should not respond to AppendEntries messages. handleAppendEntries :: RPCHandler 'Leader sm (AppendEntries v) v handleAppendEntriesResponse :: forall sm v. RPCHandler 'Leader sm AppendEntriesResponse v -- | Leaders should not respond to RequestVote messages. handleRequestVote :: RPCHandler 'Leader sm RequestVote v -- | Leaders should not respond to RequestVoteResponse messages. handleRequestVoteResponse :: RPCHandler 'Leader sm RequestVoteResponse v handleTimeout :: Show v => TimeoutHandler 'Leader sm v handleClientReadRequest :: (Show v, Serialize v) => ClientReqHandler 'Leader ClientReadReq sm v handleClientWriteRequest :: (Show v, Serialize v) => ClientReqHandler 'Leader (ClientWriteReq v) sm v module Raft.Follower -- | Handle AppendEntries RPC message from Leader Sections 5.2 and 5.3 of -- Raft Paper & Figure 2: Receiver Implementation -- -- Note: see PersistentState datatype for discussion about not -- keeping the entire log in memory. handleAppendEntries :: forall v sm. Show v => RPCHandler 'Follower sm (AppendEntries v) v -- | Followers should not respond to AppendEntriesResponse messages. handleAppendEntriesResponse :: RPCHandler 'Follower sm AppendEntriesResponse v handleRequestVote :: RPCHandler 'Follower sm RequestVote v -- | Followers should not respond to RequestVoteResponse messages. handleRequestVoteResponse :: RPCHandler 'Follower sm RequestVoteResponse v -- | Follower converts to Candidate if handling ElectionTimeout handleTimeout :: TimeoutHandler 'Follower sm v -- | When a client handles a client request, it redirects the client to the -- current leader by responding with the current leader id, if it knows -- of one. handleClientReadRequest :: ClientReqHandler 'Follower ClientReadReq sm v -- | When a client handles a client request, it redirects the client to the -- current leader by responding with the current leader id, if it knows -- of one. handleClientWriteRequest :: ClientReqHandler 'Follower (ClientWriteReq v) sm v module Raft.Candidate handleAppendEntries :: RPCHandler 'Candidate sm (AppendEntries v) v -- | Candidates should not respond to AppendEntriesResponse -- messages. handleAppendEntriesResponse :: RPCHandler 'Candidate sm AppendEntriesResponse v handleRequestVote :: RPCHandler 'Candidate sm RequestVote v -- | Candidates should not respond to RequestVoteResponse messages. handleRequestVoteResponse :: forall sm v. (Show v, Serialize v) => RPCHandler 'Candidate sm RequestVoteResponse v handleTimeout :: TimeoutHandler 'Candidate sm v handleClientReadRequest :: ClientReqHandler 'Candidate ClientReadReq sm v handleClientWriteRequest :: ClientReqHandler 'Candidate (ClientWriteReq v) sm v module Raft.Handle -- | Main entry point for handling events handleEvent :: forall sm v. (RaftStateMachinePure sm v, Show v, Serialize v) => RaftNodeState v -> TransitionEnv sm v -> PersistentState -> Event v -> (RaftNodeState v, PersistentState, [Action sm v], [LogMsg]) data RaftHandler ns sm v RaftHandler :: RPCHandler ns sm (AppendEntries v) v -> RPCHandler ns sm AppendEntriesResponse v -> RPCHandler ns sm RequestVote v -> RPCHandler ns sm RequestVoteResponse v -> TimeoutHandler ns sm v -> ClientReqHandler ns ClientReadReq sm v -> ClientReqHandler ns (ClientWriteReq v) sm v -> RaftHandler ns sm v [handleAppendEntries] :: RaftHandler ns sm v -> RPCHandler ns sm (AppendEntries v) v [handleAppendEntriesResponse] :: RaftHandler ns sm v -> RPCHandler ns sm AppendEntriesResponse v [handleRequestVote] :: RaftHandler ns sm v -> RPCHandler ns sm RequestVote v [handleRequestVoteResponse] :: RaftHandler ns sm v -> RPCHandler ns sm RequestVoteResponse v [handleTimeout] :: RaftHandler ns sm v -> TimeoutHandler ns sm v [handleClientReadRequest] :: RaftHandler ns sm v -> ClientReqHandler ns ClientReadReq sm v [handleClientWriteRequest] :: RaftHandler ns sm v -> ClientReqHandler ns (ClientWriteReq v) sm v followerRaftHandler :: (Show v, Serialize v) => RaftHandler 'Follower sm v candidateRaftHandler :: (Show v, Serialize v) => RaftHandler 'Candidate sm v leaderRaftHandler :: (Show v, Serialize v) => RaftHandler 'Leader sm v mkRaftHandler :: forall ns sm v. (Show v, Serialize v) => NodeState ns v -> RaftHandler ns sm v handleEvent' :: forall ns sm v. (RaftStateMachinePure sm v, Show v, Serialize v) => NodeState ns v -> TransitionEnv sm v -> PersistentState -> Event v -> ((ResultState ns v, [LogMsg]), PersistentState, [Action sm v]) module Raft -- | Interface to handle commands in the underlying state machine. -- Functional dependency permitting only a single state machine command -- to be defined to update the state machine. class RaftStateMachinePure sm v | sm -> v where { data family RaftStateMachinePureError sm v; type family RaftStateMachinePureCtx sm v = ctx | ctx -> sm v; } rsmTransition :: RaftStateMachinePure sm v => RaftStateMachinePureCtx sm v -> sm -> v -> Either (RaftStateMachinePureError sm v) sm class (Monad m, RaftStateMachinePure sm v) => RaftStateMachine m sm v -- | Expensive validation using global state not cacheable in -- RaftStateMachinePureCtx validateCmd :: RaftStateMachine m sm v => v -> m (Either (RaftStateMachinePureError sm v) ()) -- | Some state machines need the leader to preprocess commands issued by -- client; e.g. attaching a timestamp before creating the log entry preprocessCmd :: RaftStateMachine m sm v => v -> m v -- | Query the RaftStateMachinePureCtx value from the monadic -- context askRaftStateMachinePureCtx :: RaftStateMachine m sm v => m (RaftStateMachinePureCtx sm v) -- | Some state machines need the leader to preprocess commands issued by -- client; e.g. attaching a timestamp before creating the log entry preprocessCmd :: RaftStateMachine m sm v => v -> m v -- | Interface for nodes to send messages to one another. E.g. -- Control.Concurrent.Chan, Network.Socket, etc. class RaftSendRPC m v sendRPC :: RaftSendRPC m v => NodeId -> RPCMessage v -> m () -- | Interface for nodes to receive messages from one another class Show (RaftRecvRPCError m v) => RaftRecvRPC m v where { type family RaftRecvRPCError m v; } receiveRPC :: RaftRecvRPC m v => m (Either (RaftRecvRPCError m v) (RPCMessage v)) -- | Interface for Raft nodes to send messages to clients class RaftStateMachinePure sm v => RaftSendClient m sm v sendClient :: RaftSendClient m sm v => ClientId -> ClientResponse sm v -> m () -- | Interface for Raft nodes to receive messages from clients class Show (RaftRecvClientError m v) => RaftRecvClient m v where { type family RaftRecvClientError m v; } receiveClient :: RaftRecvClient m v => m (Either (RaftRecvClientError m v) (ClientRequest v)) -- | Provides an interface to read and write the persistent state to disk. class Monad m => RaftPersist m where { type family RaftPersistError m; } initializePersistentState :: (RaftPersist m, Exception (RaftPersistError m)) => m (Either (RaftPersistError m) ()) readPersistentState :: (RaftPersist m, Exception (RaftPersistError m)) => m (Either (RaftPersistError m) PersistentState) writePersistentState :: (RaftPersist m, Exception (RaftPersistError m)) => PersistentState -> m (Either (RaftPersistError m) ()) -- | The raft server environment composed of the concurrent variables used -- in the effectful raft layer. data RaftEnv v m RaftEnv :: RaftEventChan v m -> m () -> m () -> RaftNodeConfig -> LogCtx (RaftT v m) -> Metrics -> RaftEnv v m [eventChan] :: RaftEnv v m -> RaftEventChan v m [resetElectionTimer] :: RaftEnv v m -> m () [resetHeartbeatTimer] :: RaftEnv v m -> m () [raftNodeConfig] :: RaftEnv v m -> RaftNodeConfig [raftNodeLogCtx] :: RaftEnv v m -> LogCtx (RaftT v m) [raftNodeMetrics] :: RaftEnv v m -> Metrics -- | Run timers, RPC and client request handlers and start event loop. It -- should run forever runRaftNode :: forall m sm v. (Typeable m, Show v, Show sm, Serialize v, Show (Action sm v), Show (RaftLogError m), Show (RaftStateMachinePureError sm v), MonadIO m, MonadCatch m, MonadFail m, MonadMask m, MonadRaft v m, RaftStateMachine m sm v, RaftSendRPC m v, RaftRecvRPC m v, RaftSendClient m sm v, RaftRecvClient m v, RaftLog m v, RaftLogExceptions m, RaftPersist m, Exception (RaftPersistError m)) => RaftNodeConfig -> OptionalRaftNodeConfig -> LogCtx (RaftT v m) -> sm -> m () runRaftT :: Monad m => RaftNodeState v -> RaftEnv v m -> RaftT v m a -> m a handleEventLoop :: forall sm v m. (Show v, Serialize v, Show sm, Show (Action sm v), Show (RaftLogError m), Typeable m, MonadIO m, MonadRaft v m, MonadFail m, MonadThrow m, MonadMask m, RaftStateMachine m sm v, Show (RaftStateMachinePureError sm v), RaftPersist m, RaftSendRPC m v, RaftSendClient m sm v, RaftLog m v, RaftLogExceptions m, RaftPersist m, Exception (RaftPersistError m)) => sm -> RaftT v m () -- | Representation of a client request coupled with the client id data ClientRequest v ClientRequest :: ClientId -> ClientReq v -> ClientRequest v -- | Representation of a client request data ClientReq v -- | Request the latest state of the state machine ClientReadReq :: ClientReadReq -> ClientReq v -- | Write a command ClientWriteReq :: ClientWriteReq v -> ClientReq v -- | Request the metrics of a raft node ClientMetricsReq :: ClientMetricsReq -> ClientReq v -- | The datatype sent back to the client as an actual response data ClientResponse sm v -- | Respond with the latest state of the state machine. ClientReadResponse :: ClientReadResp sm v -> ClientResponse sm v -- | Respond with the index of the entry appended to the log ClientWriteResponse :: ClientWriteResp sm v -> ClientResponse sm v -- | Respond with the node id of the current leader ClientRedirectResponse :: ClientRedirResp -> ClientResponse sm v -- | Respond with the node's current metrics ClientMetricsResponse :: ClientMetricsResp -> ClientResponse sm v -- | Representation of a read response to a client data ClientReadResp sm v ClientReadRespStateMachine :: sm -> ClientReadResp sm v ClientReadRespEntry :: Entry v -> ClientReadResp sm v ClientReadRespEntries :: Entries v -> ClientReadResp sm v -- | Representation of a write response to a client data ClientWriteResp sm v -- | Index of the entry appended to the log due to the previous client -- request ClientWriteRespSuccess :: Index -> SerialNum -> ClientWriteResp sm v ClientWriteRespFail :: SerialNum -> RaftStateMachinePureError sm v -> ClientWriteResp sm v -- | Representation of a redirect response to a client data ClientRedirResp ClientRedirResp :: CurrentLeader -> ClientRedirResp -- | Configuration of a node in the cluster data RaftNodeConfig RaftNodeConfig :: NodeId -> NodeIds -> (Natural, Natural) -> Natural -> StorageState -> RaftNodeConfig -- | Node id of the running node [raftConfigNodeId] :: RaftNodeConfig -> NodeId -- | Set of all other node ids in the cluster [raftConfigNodeIds] :: RaftNodeConfig -> NodeIds -- | Range of times an election timeout can take [raftConfigElectionTimeout] :: RaftNodeConfig -> (Natural, Natural) -- | Heartbeat timeout timer [raftConfigHeartbeatTimeout] :: RaftNodeConfig -> Natural -- | Create a fresh DB or read from existing [raftConfigStorageState] :: RaftNodeConfig -> StorageState -- | Representation of events a raft node can send and receive data Event v MessageEvent :: MessageEvent v -> Event v TimeoutEvent :: SystemTime -> Timeout -> Event v -- | Representation of timeouts data Timeout -- | Timeout after which a follower will become candidate ElectionTimeout :: Timeout -- | Timeout after which a leader will send AppendEntries RPC to all peers HeartbeatTimeout :: Timeout -- | Representation of message events to a node data MessageEvent v -- | Incoming event from a peer RPCMessageEvent :: RPCMessage v -> MessageEvent v -- | Incoming event from a client ClientRequestEvent :: ClientRequest v -> MessageEvent v -- | Representation of an entry in the replicated log data Entry v Entry :: Index -> Term -> EntryValue v -> EntryIssuer -> EntryHash -> Entry v -- | Index of entry in the log [entryIndex] :: Entry v -> Index -- | Term when entry was received by leader [entryTerm] :: Entry v -> Term -- | Command to update state machine [entryValue] :: Entry v -> EntryValue v -- | Id of the client that issued the command [entryIssuer] :: Entry v -> EntryIssuer [entryPrevHash] :: Entry v -> EntryHash type Entries v = Seq (Entry v) -- | Provides an interface for nodes to write log entries to storage. class (Show (RaftWriteLogError m), Monad m) => RaftWriteLog m v where { type family RaftWriteLogError m; } -- | Write the given log entries to storage writeLogEntries :: (RaftWriteLog m v, Exception (RaftWriteLogError m)) => Entries v -> m (Either (RaftWriteLogError m) ()) data DeleteSuccess v DeleteSuccess :: DeleteSuccess v -- | Provides an interface for nodes to delete log entries from storage. class (Show (RaftDeleteLogError m), Monad m) => RaftDeleteLog m v where { type family RaftDeleteLogError m; } -- | Delete log entries from a given index; e.g. 'deleteLogEntriesFrom 7' -- should delete every log entry with an index >= 7. deleteLogEntriesFrom :: (RaftDeleteLog m v, Exception (RaftDeleteLogError m)) => Index -> m (Either (RaftDeleteLogError m) (DeleteSuccess v)) -- | Provides an interface for nodes to read log entries from storage. class (Show (RaftReadLogError m), Monad m) => RaftReadLog m v where { type family RaftReadLogError m; } -- | Read the log at a given index readLogEntry :: (RaftReadLog m v, Exception (RaftReadLogError m)) => Index -> m (Either (RaftReadLogError m) (Maybe (Entry v))) -- | Read log entries from a specific index onwards, including the specific -- index readLogEntriesFrom :: (RaftReadLog m v, Exception (RaftReadLogError m)) => Index -> m (Either (RaftReadLogError m) (Entries v)) -- | Read the last log entry in the log readLastLogEntry :: (RaftReadLog m v, Exception (RaftReadLogError m)) => m (Either (RaftReadLogError m) (Maybe (Entry v))) -- | Read log entries from a specific index onwards, including the specific -- index readLogEntriesFrom :: (RaftReadLog m v, Exception (RaftReadLogError m)) => Index -> m (Either (RaftReadLogError m) (Entries v)) type RaftLog m v = (RaftInitLog m v, RaftReadLog m v, RaftWriteLog m v, RaftDeleteLog m v) -- | Representation of possible errors that come from reading, writing or -- deleting logs from the persistent storage data RaftLogError m type RaftLogExceptions m = (Exception (RaftInitLogError m), Exception (RaftReadLogError m), Exception (RaftWriteLogError m), Exception (RaftDeleteLogError m)) -- | Representation of the logs' context data LogCtx m LogCtx :: LogDest m -> Severity -> LogCtx m [logCtxDest] :: LogCtx m -> LogDest m [logCtxSeverity] :: LogCtx m -> Severity NoLogs :: LogCtx m -- | Representation of the logs' destination data LogDest m LogWith :: (MonadIO m => Severity -> Text -> m ()) -> LogDest m LogFile :: FilePath -> LogDest m LogStdout :: LogDest m -- | Representation of the severity of the logs data Severity Debug :: Severity Info :: Severity Critical :: Severity data Mode Follower :: Mode Candidate :: Mode Leader :: Mode -- | Existential type hiding the internal node state data RaftNodeState v [RaftNodeState] :: {unRaftNodeState :: NodeState s v} -> RaftNodeState v -- | The volatile state of a Raft Node data NodeState (a :: Mode) v [NodeFollowerState] :: FollowerState v -> NodeState 'Follower v [NodeCandidateState] :: CandidateState v -> NodeState 'Candidate v [NodeLeaderState] :: LeaderState v -> NodeState 'Leader v -- | Representation of the current leader in the cluster. The system is -- considered to be unavailable if there is no leader data CurrentLeader CurrentLeader :: LeaderId -> CurrentLeader NoLeader :: CurrentLeader data FollowerState v FollowerState :: CurrentLeader -> Index -> Index -> LastLogEntry v -> Maybe Term -> ClientWriteReqCache -> FollowerState v -- | Id of the current leader [fsCurrentLeader] :: FollowerState v -> CurrentLeader -- | Index of highest log entry known to be committed [fsCommitIndex] :: FollowerState v -> Index -- | Index of highest log entry applied to state machine [fsLastApplied] :: FollowerState v -> Index -- | Index and term of the last log entry in the node's log [fsLastLogEntry] :: FollowerState v -> LastLogEntry v -- | The term of the log entry specified in and AppendEntriesRPC [fsTermAtAEPrevIndex] :: FollowerState v -> Maybe Term -- | The client write request cache, growing linearly with the number of -- clients [fsClientReqCache] :: FollowerState v -> ClientWriteReqCache data CandidateState v CandidateState :: Index -> Index -> NodeIds -> LastLogEntry v -> ClientWriteReqCache -> CandidateState v -- | Index of highest log entry known to be committed [csCommitIndex] :: CandidateState v -> Index -- | Index of highest log entry applied to state machine [csLastApplied] :: CandidateState v -> Index -- | Votes from other nodes in the raft network [csVotes] :: CandidateState v -> NodeIds -- | Index and term of the last log entry in the node's log [csLastLogEntry] :: CandidateState v -> LastLogEntry v -- | The client write request cache, growing linearly with the number of -- clients [csClientReqCache] :: CandidateState v -> ClientWriteReqCache data LeaderState v LeaderState :: Index -> Index -> Map NodeId Index -> Map NodeId Index -> LastLogEntry v -> Int -> ClientReadReqs -> ClientWriteReqCache -> LeaderState v -- | Index of highest log entry known to be committed [lsCommitIndex] :: LeaderState v -> Index -- | Index of highest log entry applied to state machine [lsLastApplied] :: LeaderState v -> Index -- | For each server, index of the next log entry to send to that server [lsNextIndex] :: LeaderState v -> Map NodeId Index -- | For each server, index of highest log entry known to be replicated on -- server [lsMatchIndex] :: LeaderState v -> Map NodeId Index -- | Index, term, and client id of the last log entry in the node's log. -- The only time `Maybe ClientId` will be Nothing is at the initial term. [lsLastLogEntry] :: LeaderState v -> LastLogEntry v -- | Number of read requests handled this term [lsReadReqsHandled] :: LeaderState v -> Int -- | The number of successful responses received regarding a specific read -- request heartbeat. [lsReadRequest] :: LeaderState v -> ClientReadReqs -- | The cache of client write requests received by the leader [lsClientReqCache] :: LeaderState v -> ClientWriteReqCache -- | A node in Raft begins as a follower initRaftNodeState :: RaftNodeState v -- | Check if node is in a follower state isFollower :: NodeState s v -> Bool -- | Check if node is in a candidate state isCandidate :: NodeState s v -> Bool -- | Check if node is in a leader state isLeader :: NodeState s v -> Bool -- | Update the last log entry in the node's log setLastLogEntry :: NodeState s v -> Entries v -> NodeState s v -- | Get the last applied index and the commit index of the last log entry -- in the node's log getLastLogEntry :: NodeState ns v -> LastLogEntry v -- | Get the index of highest log entry applied to state machine and the -- index of highest log entry known to be committed getLastAppliedAndCommitIndex :: NodeState ns v -> (Index, Index) -- | Persistent state that all Raft nodes maintain, regardless of node -- state. data PersistentState PersistentState :: !Term -> !Maybe NodeId -> PersistentState -- | Last term server has seen [currentTerm] :: PersistentState -> !Term -- | Candidate id that received vote in current term [votedFor] :: PersistentState -> !Maybe NodeId -- | A node initiates its persistent state with term 0 and with its vote -- blank initPersistentState :: PersistentState -- | Unique identifier of a Raft node type NodeId = ByteString type NodeIds = Set NodeId -- | Unique identifier of a client newtype ClientId ClientId :: NodeId -> ClientId -- | Unique identifier of a leader newtype LeaderId LeaderId :: NodeId -> LeaderId [unLeaderId] :: LeaderId -> NodeId -- | Representation of monotonic election terms newtype Term Term :: Natural -> Term -- | Representation of monotonic indices newtype Index Index :: Natural -> Index -- | Initial term. Terms start at 0 term0 :: Term -- | Initial index. Indeces start at 0 index0 :: Index data RPC v AppendEntriesRPC :: AppendEntries v -> RPC v AppendEntriesResponseRPC :: AppendEntriesResponse -> RPC v RequestVoteRPC :: RequestVote -> RPC v RequestVoteResponseRPC :: RequestVoteResponse -> RPC v class RPCType a v toRPC :: RPCType a v => a -> RPC v -- | Representation of a message sent between nodes data RPCMessage v RPCMessage :: NodeId -> RPC v -> RPCMessage v [sender] :: RPCMessage v -> NodeId [rpc] :: RPCMessage v -> RPC v -- | Representation of a message sent from a leader to its peers data AppendEntries v AppendEntries :: Term -> LeaderId -> Index -> Term -> Entries v -> Index -> Maybe Int -> AppendEntries v -- | Leader's term [aeTerm] :: AppendEntries v -> Term -- | Leader's identifier so that followers can redirect clients [aeLeaderId] :: AppendEntries v -> LeaderId -- | Index of log entry immediately preceding new ones [aePrevLogIndex] :: AppendEntries v -> Index -- | Term of aePrevLogIndex entry [aePrevLogTerm] :: AppendEntries v -> Term -- | Log entries to store (empty for heartbeat) [aeEntries] :: AppendEntries v -> Entries v -- | Leader's commit index [aeLeaderCommit] :: AppendEntries v -> Index -- | which read request the message corresponds to [aeReadRequest] :: AppendEntries v -> Maybe Int -- | Representation of the response from a follower to an AppendEntries -- message data AppendEntriesResponse AppendEntriesResponse :: Term -> Bool -> Maybe Int -> AppendEntriesResponse -- | current term for leader to update itself [aerTerm] :: AppendEntriesResponse -> Term -- | true if follower contained entry matching aePrevLogIndex and -- aePrevLogTerm [aerSuccess] :: AppendEntriesResponse -> Bool -- | which read request the response corresponds to [aerReadRequest] :: AppendEntriesResponse -> Maybe Int -- | Representation of the message sent by candidates to their peers to -- request their vote data RequestVote RequestVote :: Term -> NodeId -> Index -> Term -> RequestVote -- | candidates term [rvTerm] :: RequestVote -> Term -- | candidate requesting vote [rvCandidateId] :: RequestVote -> NodeId -- | index of candidate's last log entry [rvLastLogIndex] :: RequestVote -> Index -- | term of candidate's last log entry [rvLastLogTerm] :: RequestVote -> Term -- | Representation of a response to a RequestVote message data RequestVoteResponse RequestVoteResponse :: Term -> Bool -> RequestVoteResponse -- | current term for candidate to update itself [rvrTerm] :: RequestVoteResponse -> Term -- | true means candidate recieved vote [rvrVoteGranted] :: RequestVoteResponse -> Bool -- | The data used to construct an AppendEntries value, snapshotted from -- the node state at the time the AppendEntries val should be created. data AppendEntriesData v AppendEntriesData :: Term -> Index -> AppendEntriesSpec v -> AppendEntriesData v [aedTerm] :: AppendEntriesData v -> Term [aedLeaderCommit] :: AppendEntriesData v -> Index [aedEntriesSpec] :: AppendEntriesData v -> AppendEntriesSpec v module Examples.Raft.Socket.Common -- | Convert a host and a port to a valid NodeId hostPortToNid :: (HostName, ServiceName) -> NodeId hostPortToNidBS :: (HostName, ServiceName) -> ByteString -- | Retrieve the host and port from a valid NodeId nidToHostPort :: NodeId -> (HostName, ServiceName) -- | Get a free port number. getFreePort :: IO PortNumber -- | Receive bytes on a socket until an entire message can be decoded. This -- function fixes the deserialization of the bytes sent on the socket to -- the implementation of the Serialize typeclass. recvSerialized :: Serialize a => Socket -> IO (Maybe a) module Examples.Raft.Socket.Node data ResponseSignal sm v -- | we managed to write a valid response to the TMVar OkResponse :: ClientResponse sm v -> ResponseSignal sm v -- | if we get overlapping requests coming in with the same client id, we -- "kill" one of them DeadResponse :: ResponseSignal sm v data NodeSocketEnv sm v NodeSocketEnv :: TChan (RPCMessage v) -> TChan (ClientRequest v) -> TVar (Map ClientId (TMVar (ResponseSignal sm v))) -> NodeSocketEnv sm v -- | Queue of RPC messages to be processed by event handlers [nsMsgQueue] :: NodeSocketEnv sm v -> TChan (RPCMessage v) -- | Queue of client request messages to be processed by event handlers [nsClientReqQueue] :: NodeSocketEnv sm v -> TChan (ClientRequest v) -- | Map of variables to which responses to a request are written. N.B.: -- this assumes a client id uniquely identifies a request; A client will -- never send a request without having either 1) given up on the a -- previous request because of a timeout, or 2) received a response to -- each previous request issued. [nsClientReqResps] :: NodeSocketEnv sm v -> TVar (Map ClientId (TMVar (ResponseSignal sm v))) newtype RaftSocketT sm v m a RaftSocketT :: ReaderT (NodeSocketEnv sm v) m a -> RaftSocketT sm v m a [unRaftSocketT] :: RaftSocketT sm v m a -> ReaderT (NodeSocketEnv sm v) m a runRaftSocketT :: MonadIO m => NodeSocketEnv sm v -> RaftSocketT sm v m a -> m a acceptConnections :: forall sm v m. (Serialize sm, Serialize v, Serialize (RaftStateMachinePureError sm v), Show (RaftStateMachinePureError sm v), MonadIO m) => HostName -> ServiceName -> RaftSocketT sm v m () instance Control.Monad.Trans.Class.MonadTrans (Examples.Raft.Socket.Node.RaftSocketT sm v) instance GHC.Base.MonadPlus m => GHC.Base.MonadPlus (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance GHC.Base.Alternative m => GHC.Base.Alternative (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (Examples.Raft.Socket.Node.NodeSocketEnv sm v) (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance Control.Monad.Fail.MonadFail m => Control.Monad.Fail.MonadFail (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance GHC.Base.Monad m => GHC.Base.Monad (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance GHC.Base.Applicative m => GHC.Base.Applicative (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance GHC.Base.Functor m => GHC.Base.Functor (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance (Raft.StateMachine.RaftStateMachinePure sm v, Control.Monad.Catch.MonadMask m, Control.Monad.Catch.MonadCatch m, Control.Monad.IO.Class.MonadIO m, Data.Serialize.Serialize sm, Data.Serialize.Serialize v) => Raft.Client.RaftSendClient (Examples.Raft.Socket.Node.RaftSocketT sm v m) sm v instance (Control.Monad.IO.Class.MonadIO m, Data.Serialize.Serialize v) => Raft.Client.RaftRecvClient (Examples.Raft.Socket.Node.RaftSocketT sm v m) v instance (Control.Monad.Catch.MonadCatch m, Control.Monad.Catch.MonadMask m, Control.Monad.IO.Class.MonadIO m, Data.Serialize.Serialize v, GHC.Show.Show v) => Raft.RPC.RaftSendRPC (Examples.Raft.Socket.Node.RaftSocketT sm v m) v instance (Control.Monad.IO.Class.MonadIO m, GHC.Show.Show v) => Raft.RPC.RaftRecvRPC (Examples.Raft.Socket.Node.RaftSocketT sm v m) v instance (Control.Monad.IO.Class.MonadIO m, Raft.Persistent.RaftPersist m) => Raft.Persistent.RaftPersist (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance (Control.Monad.IO.Class.MonadIO m, Raft.Log.RaftInitLog m v) => Raft.Log.RaftInitLog (Examples.Raft.Socket.Node.RaftSocketT sm v m) v instance Raft.Log.RaftWriteLog m v => Raft.Log.RaftWriteLog (Examples.Raft.Socket.Node.RaftSocketT sm v m) v instance Raft.Log.RaftReadLog m v => Raft.Log.RaftReadLog (Examples.Raft.Socket.Node.RaftSocketT sm v m) v instance Raft.Log.RaftDeleteLog m v => Raft.Log.RaftDeleteLog (Examples.Raft.Socket.Node.RaftSocketT sm v m) v instance Raft.StateMachine.RaftStateMachine m sm v => Raft.StateMachine.RaftStateMachine (Examples.Raft.Socket.Node.RaftSocketT sm v m) sm v instance Raft.Monad.MonadRaftChan v m => Raft.Monad.MonadRaftChan v (Examples.Raft.Socket.Node.RaftSocketT sm v m) instance (Control.Monad.IO.Class.MonadIO m, Raft.Monad.MonadRaftFork m) => Raft.Monad.MonadRaftFork (Examples.Raft.Socket.Node.RaftSocketT sm v m) module Examples.Raft.Socket.Client newtype ClientRespChan s v ClientRespChan :: TChan (STM IO) (ClientResponse s v) -> ClientRespChan s v [clientRespChan] :: ClientRespChan s v -> TChan (STM IO) (ClientResponse s v) newClientRespChan :: IO (ClientRespChan s v) newtype RaftClientRespChanT s v m a RaftClientRespChanT :: ReaderT (ClientRespChan s v) m a -> RaftClientRespChanT s v m a [unRaftClientRespChanT] :: RaftClientRespChanT s v m a -> ReaderT (ClientRespChan s v) m a type RaftSocketClientM s v = RaftClientT s v (RaftClientRespChanT s v IO) runRaftSocketClientM :: ClientId -> Set NodeId -> ClientRespChan s v -> RaftSocketClientM s v a -> IO a -- | Send a client read request using the example socket interface of -- RaftSocketClientM socketClientRead :: (Serialize s, Serialize v, Serialize (RaftStateMachinePureError s v), Show s, Show v, Show (RaftClientError s v (RaftSocketClientM s v)), Show (RaftStateMachinePureError s v)) => ClientReadReq -> RaftSocketClientM s v (Either Text (ClientReadResp s v)) socketClientWrite :: (Serialize s, Serialize v, Serialize (RaftStateMachinePureError s v), Show s, Show v, Show (RaftClientError s v (RaftSocketClientM s v)), Show (RaftStateMachinePureError s v)) => v -> RaftSocketClientM s v (Either Text (ClientWriteResp s v)) instance GHC.Base.MonadPlus m => GHC.Base.MonadPlus (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance GHC.Base.Alternative m => GHC.Base.Alternative (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader (Examples.Raft.Socket.Client.ClientRespChan s v) (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance GHC.Base.Monad m => GHC.Base.Monad (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance GHC.Base.Applicative m => GHC.Base.Applicative (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance GHC.Base.Functor m => GHC.Base.Functor (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance Control.Monad.Base.MonadBase GHC.Types.IO m => Control.Monad.Base.MonadBase GHC.Types.IO (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance Control.Monad.STM.Class.MonadSTM m => Control.Monad.STM.Class.MonadSTM (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance Control.Monad.Trans.Class.MonadTrans (Examples.Raft.Socket.Client.RaftClientRespChanT s v) instance Control.Monad.Trans.Control.MonadTransControl (Examples.Raft.Socket.Client.RaftClientRespChanT s v) instance Control.Monad.Trans.Control.MonadBaseControl GHC.Types.IO m => Control.Monad.Trans.Control.MonadBaseControl GHC.Types.IO (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance System.Console.Haskeline.MonadException.MonadException m => System.Console.Haskeline.MonadException.MonadException (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) instance (Data.Serialize.Serialize s, Data.Serialize.Serialize v, Data.Serialize.Serialize (Raft.StateMachine.RaftStateMachinePureError s v), Control.Monad.IO.Class.MonadIO m) => Raft.Client.RaftClientSend (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) v instance (Data.Serialize.Serialize s, Data.Serialize.Serialize v, Control.Monad.IO.Class.MonadIO m) => Raft.Client.RaftClientRecv (Examples.Raft.Socket.Client.RaftClientRespChanT s v m) s v module Examples.Raft.FileStore.Log newtype RaftLogFileStoreError RaftLogFileStoreError :: Text -> RaftLogFileStoreError newtype RaftLogFile RaftLogFile :: FilePath -> RaftLogFile [unRaftLogFile] :: RaftLogFile -> FilePath newtype RaftLogFileStoreT m a RaftLogFileStoreT :: ReaderT RaftLogFile m a -> RaftLogFileStoreT m a [unRaftLogFileStoreT] :: RaftLogFileStoreT m a -> ReaderT RaftLogFile m a runRaftLogFileStoreT :: RaftLogFile -> RaftLogFileStoreT m a -> m a readLogEntries :: (MonadIO m, Serialize v) => RaftLogFileStoreT m (Either Text (Entries v)) instance Control.Monad.Trans.Class.MonadTrans Examples.Raft.FileStore.Log.RaftLogFileStoreT instance GHC.Base.MonadPlus m => GHC.Base.MonadPlus (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance GHC.Base.Alternative m => GHC.Base.Alternative (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance GHC.Base.Monad m => Control.Monad.Reader.Class.MonadReader Examples.Raft.FileStore.Log.RaftLogFile (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance Control.Monad.Fail.MonadFail m => Control.Monad.Fail.MonadFail (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance GHC.Base.Monad m => GHC.Base.Monad (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance GHC.Base.Applicative m => GHC.Base.Applicative (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance GHC.Base.Functor m => GHC.Base.Functor (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance GHC.Show.Show Examples.Raft.FileStore.Log.RaftLogFileStoreError instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance (Data.Serialize.Serialize v, Control.Monad.IO.Class.MonadIO m) => Raft.Log.RaftInitLog (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) v instance (Control.Monad.IO.Class.MonadIO m, Data.Serialize.Serialize v) => Raft.Log.RaftWriteLog (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) v instance (Control.Monad.IO.Class.MonadIO m, Data.Serialize.Serialize v) => Raft.Log.RaftReadLog (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) v instance (Control.Monad.IO.Class.MonadIO m, Data.Serialize.Serialize v) => Raft.Log.RaftDeleteLog (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) v instance Raft.Persistent.RaftPersist m => Raft.Persistent.RaftPersist (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance (GHC.Base.Monad m, Raft.RPC.RaftSendRPC m v) => Raft.RPC.RaftSendRPC (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) v instance (GHC.Base.Monad m, Raft.RPC.RaftRecvRPC m v) => Raft.RPC.RaftRecvRPC (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) v instance (GHC.Base.Monad m, Raft.Client.RaftSendClient m sm v) => Raft.Client.RaftSendClient (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) sm v instance (GHC.Base.Monad m, Raft.Client.RaftRecvClient m v) => Raft.Client.RaftRecvClient (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) v instance Raft.StateMachine.RaftStateMachine m sm v => Raft.StateMachine.RaftStateMachine (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) sm v instance Raft.Monad.MonadRaftChan v m => Raft.Monad.MonadRaftChan v (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance (Control.Monad.IO.Class.MonadIO m, Raft.Monad.MonadRaftFork m) => Raft.Monad.MonadRaftFork (Examples.Raft.FileStore.Log.RaftLogFileStoreT m) instance GHC.Exception.Type.Exception Examples.Raft.FileStore.Log.RaftLogFileStoreError