Timings for proof.v
- /home/gitlab-runner/builds/v6HyzL39/0/coq/coq/_bench/opam.OLD/ocaml-OLD/.opam-switch/build/coq-perennial.dev/./src/program_proof/vrsm/reconfig/proof.v.timing
- /home/gitlab-runner/builds/v6HyzL39/0/coq/coq/_bench/opam.NEW/ocaml-NEW/.opam-switch/build/coq-perennial.dev/./src/program_proof/vrsm/reconfig/proof.v.timing
From Perennial.program_proof Require Import grove_prelude.
From Goose.github_com.mit_pdos.gokv.vrsm Require Export reconfig.
From Perennial.program_proof.grove_shared Require Import urpc_proof urpc_spec.
From Perennial.goose_lang.lib Require Import waitgroup.
From iris.base_logic Require Export lib.ghost_var mono_nat.
From iris.algebra Require Import dfrac_agree mono_list.
From Perennial.program_proof.vrsm.replica Require Import
config_protocol_proof getstate_proof
setstate_proof makeclerk_proof becomeprimary_proof.
Context {params:pbParams.t}.
Notation OpType := (Sm.OpType pb_record).
Notation has_op_encoding := (Sm.has_op_encoding pb_record).
Notation has_snap_encoding := (Sm.has_snap_encoding pb_record).
Notation compute_reply := (Sm.compute_reply pb_record).
Context `{!waitgroupG Σ}.
Definition adminN := nroot .@ "admin".
Lemma wp_Reconfig γ configHosts_sl (configHosts:list u64) (servers:list u64) (servers_sl:Slice.t) server_γs :
{{{
"Hservers_sl" ∷ own_slice servers_sl uint64T 1 servers ∗
"#HconfHost_sl" ∷ readonly (own_slice_small configHosts_sl uint64T 1 configHosts) ∗
"#Hhost" ∷ ([∗ list] γsrv ; host ∈ server_γs ; servers, is_pb_host host γ γsrv) ∗
"#Hconf_host" ∷ is_pb_config_hosts configHosts γ
}}}
EnterNewConfig (slice_val configHosts_sl) (slice_val servers_sl)
{{{
(err:u64), RET #err; True
}}}.
iDestruct (own_slice_sz with "Hservers_sl") as %Hservers_sz.
wp_apply (wp_MakeClerk2 with "[Hconf_host]").
iIntros (ck γconf) "#Hck".
wp_bind (Clerk__ReserveEpochAndGetConfig _).
iApply (wp_frame_wand with "[HΦ Hservers_sl]").
wp_apply (wp_Clerk_ReserveEpochAndGetConfig2 with "[$Hck]").
iIntros (?????) "Hpost1".
wp_apply wp_RandomUint64.
set (s:=(u64_instance.u64.(word.add) rnd (U64 1))).
iDestruct "Hpost1" as "(Hconf_sl & #Hres & Hconf_unset & Hprop & Hinit & #His_conf & #Hskip & #His_hosts & #Hlb)".
iAssert (⌜length conf ≠ 0⌝)%I as %Hold_conf_ne.
iDestruct "His_conf" as "(_ & _ & %Hconfγ_nz)".
iDestruct (big_sepL2_length with "His_hosts") as %Heq.
rewrite fmap_length in Hconfγ_nz.
iMod (readonly_load with "Hconf_sl") as (?) "Hconf_sl2".
iDestruct (own_slice_small_sz with "Hconf_sl2") as %Hconf_len.
set (oldNodeId:=word.modu randId config_sl.(Slice.sz)).
assert (int.nat oldNodeId < length conf) as Hlookup_conf.
enough (int.Z randId `mod` int.Z config_sl.(Slice.sz) < int.Z config_sl.(Slice.sz))%Z.
apply lookup_lt_is_Some_2 in Hlookup_conf as [host Hlookup_conf].
wp_apply (wp_SliceGet with "[$Hconf_sl2]").
(* FIXME: how does wp_MakeClerk work here? *)
iDestruct (big_sepL2_lookup_2_some with "His_hosts") as %HH.
destruct HH as [γsrv_old Hconfγ_lookup].
iRename "His_hosts" into "His_hosts_full".
iAssert ([∗ list] γsrv;host0 ∈ confγs;conf, is_pb_rpcs host0 γ γsrv)%I with "[]" as "#His_hosts".
iApply (big_sepL2_impl with "[$]").
wp_apply (makeclerk_proof.wp_MakeClerk with "[]").
iDestruct (big_sepL2_lookup_acc with "His_hosts") as "[HisHost _]".
iDestruct "HisHost" as "HisHost".
iIntros (oldClerk) "#HoldClerk".
wp_apply (wp_allocStruct).
iDestruct (struct_fields_split with "Hargs") as "HH".
wp_apply (wp_Clerk__GetState with "[$HoldClerk $Epoch]").
eapply elem_of_list_lookup_2.
rewrite list_lookup_fmap.
by setoid_rewrite Hconfγ_lookup.
iIntros (reply err) "Hpost".
destruct (decide (err = _)); last first.
rewrite bool_decide_false; last naive_solver.
(* err = 0; keep going with reconfig *)
(* Got the old state now *)
iDestruct "Hpost" as (????) "(%Hepoch_lb_ineq & %Hepoch_ub_ineq & #Hacc_ro & #Hprop_facts & #Hprim_facts & #Hprop_lb & #HcommitFacts & Hreply & %Henc & %Hlen_no_overflow)".
destruct (decide (int.nat epochacc = int.nat epoch)) as [Heq|Hepochacc_ne_epoch].
replace (epochacc) with (epoch) by word.
iApply (own_unused_facts_false with "[$] [$]").
iMod (ghost_init_primary with "Hprop_lb Hprop_facts His_conf Hacc_ro Hskip Hprop") as "Hprim".
apply elem_of_list_fmap_1.
by eapply elem_of_list_lookup_2.
iMod (primary_ghost_init_primary with "Hinit") as "[#Hinit #Hprim_facts]".
(*
iApply fupd_wp.
iMod (fupd_mask_subseteq (↑pbN)) as "Hmask".
{ set_solver. }
iClear "Hprim_facts".
iDestruct (ghost_get_propose_lb with "Hprop") as "#Hprop_lb2".
iMod (primary_ghost_init_primary (own_primary_ghost γ.(s_pb) epoch opsfull)
with "Hinit [Hprop]") as "#[Hescrow Hprim_facts]".
{ iFrame "∗#". }
iMod "Hmask". iModIntro. *)
iIntros (clerks_sl) "Hclerks_sl".
iDestruct (own_slice_to_small with "Hservers_sl") as "Hservers_sl".
iDestruct (own_slice_to_small with "Hclerks_sl") as "Hclerks_sl".
iDestruct (own_slice_small_sz with "Hclerks_sl") as %Hclerks_sz.
rewrite replicate_length in Hclerks_sz.
(* weaken to loop invariant *)
iAssert (
∃ (i:u64) clerksComplete clerksLeft,
"Hi" ∷ i_ptr ↦[uint64T] #i ∗
"%HcompleteLen" ∷ ⌜length clerksComplete = int.nat i⌝ ∗
"%Hlen" ∷ ⌜length (clerksComplete ++ clerksLeft) = length servers⌝ ∗
"Hclerks_sl" ∷ own_slice_small clerks_sl ptrT 1 (clerksComplete ++ clerksLeft) ∗
"Hservers_sl" ∷ own_slice_small servers_sl uint64T 1 servers ∗
"#Hclerks_is" ∷ ([∗ list] ck ; γsrv ∈ clerksComplete ; (take (length clerksComplete) server_γs),
is_Clerk ck γ γsrv
)
)%I with "[Hclerks_sl Hservers_sl Hi]" as "HH".
assert (int.nat i < length servers) as Hlookup.
apply list_lookup_lt in Hlookup as [host Hlookup].
wp_apply (wp_SliceGet with "[$Hservers_sl]").
iDestruct (big_sepL2_lookup_2_some with "Hhost") as %HH.
destruct HH as [γsrv Hserver_γs_lookup].
wp_apply (wp_MakeClerk with "[]").
iDestruct (big_sepL2_lookup_acc with "Hhost") as "[H _]".
wp_apply (wp_SliceSet (V:=loc) with "[Hclerks_sl]").
instantiate (1:=clerksComplete ++ [pbCk]).
instantiate (2:=tail clerksLeft).
rewrite app_nil_r in Hlen.
replace (length _) with (length clerksComplete + 0) by lia.
iDestruct (big_sepL2_length with "Hhost") as %Hserver_len_eq.
rewrite take_more; last first.
iApply (big_sepL2_app with "Hclerks_is []").
replace (take 1 (drop (_) server_γs)) with ([γsrv]); last first.
apply ListSolver.list_eq_bounded.
rewrite list_lookup_singleton.
rewrite lookup_take; last first.
rewrite -Hserver_γs_lookup.
iApply big_sepL2_singleton.
assert (int.nat i = length servers) as Hi_done.
rewrite app_length in Hlen.
replace (clerksLeft) with ([] : list loc) in *; last first.
(* TODO: list_solver. pure fact *)
enough (length clerksLeft = 0).
rewrite app_length in Hlen.
wp_apply (wp_NewWaitGroup_free).
iIntros (errs_sl) "Herrs_sl".
iDestruct (slice.own_slice_sz with "Herrs_sl") as "%Herrs_sz".
rename clerksComplete into clerks.
iMod (fupd_mask_subseteq (↑adminN)) as "Hmask".
set (P:= (λ i, ∃ (err:u64) γsrv',
⌜server_γs !! int.nat i = Some γsrv'⌝ ∗
readonly ((errs_sl.(Slice.ptr) +ₗ[uint64T] int.Z i)↦[uint64T] #err) ∗
□ if (decide (err = U64 0)) then
protocol.is_epoch_lb γsrv'.(r_pb) epoch
else
True
)%I : u64 → iProp Σ).
iMod (free_WaitGroup_alloc adminN _ P with "Hwg") as (γwg) "Hwg".
(* iMod (readonly_alloc_1 with "Hreply_epoch") as "#Hreply_epoch". *)
iMod (readonly_alloc_1 with "Hreply_state") as "#Hreply_state".
iMod (readonly_alloc_1 with "Hreply_next_index") as "#Hreply_next_index".
iMod (readonly_alloc_1 with "Hreply_committed_next_index") as "#Hreply_committed_next_index".
iDestruct "Hreply_state_sl" as "#Hreply_state_sl".
(* weaken to loop invariant *)
iAssert (
∃ (i:u64),
"Hi" ∷ i_ptr ↦[uint64T] #i ∗
"%Hi_ineq" ∷ ⌜int.nat i ≤ length clerks⌝ ∗
"Herrs" ∷ (errs_sl.(Slice.ptr) +ₗ[uint64T] int.Z i)↦∗[uint64T] (replicate (int.nat clerks_sl.(Slice.sz)- int.nat i) #0) ∗
"Hwg" ∷ own_WaitGroup adminN wg γwg i P
)%I with "[Herrs_sl Hi Hwg]" as "HH".
unfold slice.own_slice_small.
iDestruct "Herrs_sl" as "[[Herrs_sl %Hlen] _]".
destruct Hlen as [Hlen _].
iSplitR; first iPureIntro.
replace (1 * int.Z _)%Z with (0%Z) by word.
replace (int.nat _ - int.nat 0) with (int.nat clerks_sl.(Slice.sz)) by word.
(* FIXME: copy/pasted from pb_apply_proof *)
iMod (own_update with "Hconf_unset") as "Hconf_prop".
apply cmra_update_exclusive.
instantiate (1:=(to_dfrac_agree (DfracOwn 1) ((Some (r_pb <$> server_γs)) : (leibnizO _)))).
iMod (own_update with "Hconf_prop") as "Hconf_prop".
apply dfrac_agree_persist.
iDestruct "Hconf_prop" as "#Hconf_prop".
(* FIXME: have a lemma for this kind of loop that makes use of big_sepL's and big_sepL2's. *)
clear i HcompleteLen Heqb0 Hi_done.
wp_apply (wp_WaitGroup__Add with "[$Hwg]").
assert (int.nat i < int.nat clerks_sl.(Slice.sz)) as Hlookup by word.
rewrite -Hclerks_sz in Hlookup.
rewrite app_nil_r in Hlen.
rewrite -Hlen in Hlookup.
apply list_lookup_lt in Hlookup as [pbCk Hlookup].
wp_apply (wp_SliceGet with "[$Hclerks_sl]").
replace (int.nat clerks_sl.(Slice.sz) - int.nat i) with (S (int.nat clerks_sl.(Slice.sz) - (int.nat (word.add i 1)))) by word.
iDestruct (array_cons with "Herrs") as "[Herr_ptr Herr_ptrs]".
iDestruct (own_WaitGroup_to_is_WaitGroup with "[Hwg]") as "#His_wg".
iDestruct (ghost_get_propose_lb_facts with "Hprim") as "#[? ?]".
wp_apply (wp_fork with "[Hwg_tok Herr_ptr]").
wp_apply (wp_allocStruct).
iIntros (args_ptr) "Hargs".
iDestruct (struct_fields_split with "Hargs") as "HH".
iDestruct (big_sepL2_lookup_1_some with "Hclerks_is") as %[γsrv Hlookup2].
iDestruct (big_sepL2_lookup_acc with "Hclerks_is") as "[HH _]".
wp_apply (wp_Clerk__SetState with "[Epoch NextIndex CommittedNextIndex State]").
rewrite take_nil /= // in Hlookup2.
eapply elem_of_list_lookup_2.
rewrite list_lookup_fmap.
rewrite lookup_take_Some in Hlookup2.
destruct Hlookup2 as [-> _].
iMod (readonly_alloc_1 with "Herr_ptr") as "#Herr_ptr".
wp_apply (wp_WaitGroup__Done with "[$Hwg_tok $His_wg]").
rewrite lookup_take_Some in Hlookup2.
destruct Hlookup2 as [Hlookup2 _].
(* re-establish loop invariant *)
replace (int.Z (word.add i 1%Z)) with (int.Z i + 1)%Z by word.
wp_apply (wp_WaitGroup__Wait with "[$Hwg]").
replace (int.nat i) with (length clerks); last first.
rewrite app_nil_r in Hlen.
iIntros (err_ptr) "Herr".
(* FIXME: *)
(* This was copy/pasted and modified from apply_proof *)
iAssert (∃ (i err:u64),
"Hj" ∷ i_ptr ↦[uint64T] #i ∗
"%Hj_ub" ∷ ⌜int.nat i ≤ length clerks⌝ ∗
"Herr" ∷ err_ptr ↦[uint64T] #err ∗
"#Hrest" ∷ □ if (decide (err = (U64 0)%Z)) then
(∀ (k:u64) γsrv, ⌜int.nat k < int.nat i⌝ -∗ ⌜server_γs !! (int.nat k) = Some γsrv⌝ -∗ protocol.is_epoch_lb γsrv.(r_pb) epoch)
else
True
)%I with "[Hi Herr]" as "Hloop".
destruct (decide (_)); last first.
replace (int.nat 0%Z) with 0 in H by word.
rewrite replicate_length in Herrs_sz.
rewrite -Hclerks_sz in Herrs_sz.
rewrite app_nil_r in Hlen.
iDestruct (big_sepS_elem_of_acc _ _ i0 with "Hwg_post") as "[HH _]".
assert (int.nat i0 < int.nat errs_sl.(Slice.sz)) by word.
iDestruct "HH" as "[%Hbad|HH]".
iDestruct "HH" as (??) "(%HbackupLookup & Herr2 & Hpost)".
iEval (simpl) in "Herr2".
iMod (readonly_load with "Herr2") as (?) "Herr3".
destruct (bool_decide (_)) as [] eqn:Herr; wp_pures.
rewrite bool_decide_eq_true in Herr.
replace (err0) with (U64 0%Z) by naive_solver.
destruct (decide (err = 0%Z)).
assert (int.nat k < int.nat i0 ∨ int.nat k = int.nat i0) as [|].
replace (int.nat (word.add i0 1%Z)) with (int.nat i0 + 1) in * by word.
destruct (decide (_)); last by exfalso.
replace (γsrv') with (γsrv); last first.
replace (int.nat i0) with (int.nat k) in * by word.
iDestruct "Hpost" as "#$".
destruct (decide (err0 = _)).
(* FIXME: *)
(* End copy/paste from apply_proof *)
replace (int.nat i0) with (length clerks); last first.
destruct (decide (_)); last first.
wp_bind (Clerk__TryWriteConfig _ _ _).
iApply (wp_frame_wand with "[HΦ Hconf_sl Hclerks_sl Hprim]").
iDestruct (big_sepL2_length with "Hhost") as %Hserver_len_eq.
assert (length servers > 0) as Hserver_nz.
assert (length servers ≠ 0 ∨ length servers = 0) as [|Hbad] by word.
rewrite Hbad in Hservers_sz.
apply u64_nat_0 in Hservers_sz.
rewrite Hservers_sz in Heqb.
iMod (readonly_alloc_1 with "Hservers_sl") as "#Hservers_sl".
wp_apply (wp_Clerk__WriteConfig2 with "Hck Hservers_sl [$Hconf_prop] Hres Hhost").
(* FIXME: why manually rewrite instead of `word`? *)
apply elem_of_list_lookup_1 in Hlookup as [i Hlookup].
iDestruct (big_sepS_elem_of_acc _ _ (U64 i) with "Hwg_post") as "[HH _]".
assert (i < length server_γs).
apply lookup_lt_is_Some_1.
replace (length clerks) with (length server_γs) in * by word.
assert (int.nat i = i) as Hi.
iDestruct "HH" as "[%Hbad|HP]".
iDestruct "HP" as (??) "(%Hlookup2 & _ & Hpost)".
assert (γsrv = γsrv'.(r_pb)).
rewrite list_lookup_fmap in Hlookup.
rewrite Hlookup2 in Hlookup.
iSpecialize ("Hrest" $! i γsrv' with "[%] [%]").
(* WriteConfig succeeded *)
destruct (decide (_)); last first.
iDestruct "Hpost" as "#Hconf".
wp_apply (wp_allocStruct).
assert (0 < length clerks) as Hclerk_lookup.
apply list_lookup_lt in Hclerk_lookup as [primaryCk Hclerk_lookup].
wp_apply (wp_SliceGet with "[$Hclerks_sl]").
iDestruct (big_sepL2_lookup_1_some with "Hclerks_is") as %[γsrv Hlookup2].
iDestruct (big_sepL2_lookup_acc with "Hclerks_is") as "[HprimaryCk _]".
iDestruct (struct_fields_split with "Hargs") as "HH".
(* Get a list of γs just for backups *)
rewrite lookup_take /= in Hlookup2; last first.
replace (r) with (γsrv) in *; last first.
rewrite lookup_take /= in Hlookup2; last first.
(* set up escrow for primary *)
iMod (fupd_mask_subseteq (↑pbN)) as "Hmask".
iMod (primary_ghost_init_primary_escrow (own_primary_ghost γ.(s_pb) epoch opsfull)
with "Hinit Hprim") as "#Hescrow".
wp_apply (wp_Clerk__BecomePrimary with "[$HprimaryCk Hconf Hhost Epoch Replicas Hservers_sl]").
instantiate (1:=(marshal_proof.BecomePrimaryArgs.mkC _ _)).
iDestruct ("Hrest" with "[%] [%]") as "H".
rewrite lookup_take in Hlookup2.
instantiate (1:=servers).
iDestruct (big_sepL2_lookup_acc with "Hhost") as "[H _]".
iApply "Hrest"; last first.
replace (int.nat k) with (k).
assert (k < length servers).
apply lookup_lt_Some in H.
apply lookup_lt_Some in H.
replace (int.nat k) with (k).
assert (k < length servers).
(* FIXME: why do I have to assert this when it's already in context? *)