Section PrimaryBackup.
Context {base_params : BaseParams}.
Context {one_node_params : OneNodeParams base_params}.
Context {pb_params : PrimaryBackupParams base_params}.
Inductive name := Primary | Backup.
Proof using.
decide equality.
Qed.
Inductive msg :=
| BackItUp : input -> msg
| Ack : msg.
Proof using pb_params.
decide equality.
apply input_eq_dec.
Qed.
Inductive PB_input :=
| Request : input -> PB_input
| Read : PB_input.
Inductive PB_output :=
| RequestResponse : input -> output -> PB_output
| ReadResponse : data -> PB_output.
Record PB_data :=
{
queue : list input;
state : data
}.
Definition all_nodes : list name := [Primary; Backup].
Proof using.
unfold all_nodes.
destruct x; intuition.
Qed.
Proof using.
unfold all_nodes.
repeat constructor; intuition. simpl in *. intuition. congruence.
Qed.
Definition PB_init (n : name) :=
Build_PB_data [] init.
Definition set_queue {W O} (l : list input) :=
modify (W := W)(O := O) (fun d => Build_PB_data l (state d)).
Definition set_state {W O} (st : data) :=
modify (W := W)(O := O) (fun d => Build_PB_data (queue d) st).
Ltac pb_unfold := unfold set_queue, set_state in *; monad_unfold.
Definition PB_input_handler (h : name) (i : PB_input) (d : PB_data) :
list PB_output * PB_data * list (name * msg) :=
runGenHandler_ignore d (
match h, i with
| Primary, Request r =>
d <- get ;;
when (null (queue d)) (send (Backup, BackItUp r)) ;;
set_queue (queue d ++ [r])
| _, Read =>
d <- get ;;
write_output (ReadResponse (state d))
| _, _ => nop
end).

Lemma PB_input_handler_defn :
forall h i d os d' ms,
PB_input_handler h i d = (os, d', ms) ->
(h = Primary /\
state d' = state d /\
os = [] /\
exists r,
i = Request r /\
queue d' = queue d ++ [r] /\
(ms = [] \/ (ms = [(Backup, BackItUp r)] /\ queue d = []))) \/
(i = Read /\
d = d' /\
os = [ReadResponse (state d)] /\
ms = []) \/
(h = Backup /\
d = d' /\
ms = [] /\
os = []).