Timings for tryacquire_proof.v
- /home/gitlab-runner/builds/gGKko-aj/0/coq/coq/_bench/opam.OLD/ocaml-OLD/.opam-switch/build/coq-perennial.dev/./src/program_proof/vrsm/paxos/tryacquire_proof.v.timing
- /home/gitlab-runner/builds/gGKko-aj/0/coq/coq/_bench/opam.NEW/ocaml-NEW/.opam-switch/build/coq-perennial.dev/./src/program_proof/vrsm/paxos/tryacquire_proof.v.timing
From Perennial.program_proof Require Import grove_prelude.
From Goose.github_com.mit_pdos.gokv Require paxos.
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.goose_lang Require Import crash_borrow.
From Perennial.program_proof Require Import marshal_stateless_proof.
From Perennial Require Export paxos.definitions paxos.applyasfollower_proof.
From Perennial.base_logic Require Import lib.saved_prop.
Section tryacquire_proof.
Context `{Hparams:!paxosParams.t Σ}.
Notation ghostN := (ghostN (N:=N)).
Definition own_releaseFn_internal (f:val) γ sl_ptr oldstate : iProp Σ :=
∀ sl Φ newstate Q,
( (* precondition: *)
"Hsl_ptr" ∷ sl_ptr ↦[slice.T byteT] (slice_val sl) ∗
"#Hsl" ∷ readonly (own_slice_small sl byteT 1 newstate) ∗
"#HP" ∷ (□ Pwf newstate) ∗
"Hupd" ∷ (|={⊤∖↑ghostN,∅}=> ∃ σ, own_log γ.(s_mp) σ ∗
(⌜ get_state σ = oldstate ⌝ -∗ own_log γ.(s_mp) (σ ++ [(newstate, Q)]) ={∅,⊤∖↑ghostN}=∗ True))
) -∗
( ∀ (err:u64), ((* postcondition*)
£ 1 ∗ £ 1 ∗
if (decide (err = 0)) then
∃ σ,
is_log_lb γ.(s_mp) (σ ++ [(newstate, Q)])
else
True
) -∗ Φ #err
) -∗
WP f #() {{ Φ }}
.
Definition own_releaseFn (f:val) γ sl_ptr oldstate : iProp Σ :=
∀ sl Φ newstate,
( (* precondition: *)
"Hsl_ptr" ∷ sl_ptr ↦[slice.T byteT] (slice_val sl) ∗
"Hsl" ∷ readonly (own_slice_small sl byteT 1 newstate) ∗
"Hwf" ∷ (□ Pwf newstate) ∗
"Hupd" ∷ (|={⊤∖↑N,∅}=> ∃ oldstate', own_state γ oldstate' ∗
(⌜ oldstate' = oldstate ⌝ -∗ own_state γ newstate ={∅,⊤∖↑N}=∗ Φ #0))
) -∗
(∀ (err:u64), ⌜ err ≠ U64 0 ⌝ → Φ #err) -∗
WP f #() {{ Φ }}
.
Lemma wp_Server__TryAcquire_internal s γ γsrv :
{{{
is_Server s γ γsrv
}}}
Server__TryAcquire #s
{{{
(err:u64) (sl_ptr:loc) (rel:val), RET (#err, #sl_ptr, rel);
£ 1 ∗ £ 1 ∗
if (decide (err = 0%Z)) then
∃ sl oldstate,
sl_ptr ↦[slice.T byteT] (slice_val sl) ∗
readonly (own_slice_small sl byteT 1 oldstate) ∗
Pwf oldstate ∗
own_releaseFn_internal rel γ sl_ptr oldstate
else
True
}}}.
wp_apply wp_ref_of_zero; first done.
iIntros (err_ptr) "Herr".
wp_apply (acquire_spec with "[$]").
iIntros "[Hlocked Hown]".
wp_apply (release_spec with "[-HΦ Hlc1 Hlc2]").
repeat iExists _; iFrame "∗#".
wp_apply wp_struct_fieldRef.
setoid_rewrite decide_True; last word.
rewrite struct_field_mapsto_eq.
(* FIXME: maybe add a lemma to avoid unfolding this definition? *)
rewrite /own_releaseFn_internal.
wp_apply (wp_frame_wand with "[Hlc3 Hlc4]"); first iNamedAccu.
wp_apply (std_proof.wp_SumAssumeNoOverflow).
iAssert (ps ↦[paxosState :: "state"] (slice_val sl))%I with "[Hsl_ptr]" as "Hsl_ptr".
rewrite struct_field_mapsto_eq.
wp_apply (wp_allocStruct).
iIntros (args_ptr) "Hargs".
iDestruct (struct_fields_split with "Hargs") as "Hargs".
wp_apply (paxosState.wp_encode with "[Hepoch HaccEpoch HnextIndex HisLeader Hsl_ptr]").
instantiate (1:=paxosState.mk _ _ _ _ _).
iIntros (?) "[Hvol Henc]".
iDestruct (own_slice_to_small with "Henc") as "Henc".
wp_apply (wp_AsyncFile__Write with "[-Hvol Hlocked Hstorage Hps]").
(* this just deals with unlocking and sends the WP for the rest of the code to the fupd *)
iIntros (?) "[Hfile Hwp]".
wp_apply (release_spec with "[-Hwp]").
wp_apply (wp_wand with "Hwp").
(* start ghost reasoning *)
eapply encodes_paxosState_inj in Henc; last exact HencPaxos.
setoid_rewrite <- (assoc bi_sep).
iSplitR; first (iPureIntro; by left).
iMod (fupd_mask_subseteq _) as "Hmask".
2: iMod (ghost_leader_propose with "HleaderOnly Hlc [Hupd]") as "(HleaderOnly & #Hprop)".
iDestruct "Hupd" as (?) "[H1 Hupd]".
iMod ("Hupd" with "[% //] Hghost").
rewrite Heqb in HaccEpochEq.
repeat rewrite HaccEpochEq.
iMod (ghost_replica_accept_same_epoch with "Hghost Hprop") as "[_ Hghost]".
split_and!; try done; try word.
rewrite fmap_app last_app /= //.
(* end ghost reasoning *)
(* set (newstate:=(next_state (default [] (last st.(mp_log).*1)) op)). *)
iAssert (|={⊤}=> applyAsFollowerArgs.own args_ptr (applyAsFollowerArgs.mkC
pst.(paxosState.epoch)
(U64 (length log + 1))
newstate
))%I with "[Hargs]" as "Hargs".
iMod (readonly_alloc_1 with "epoch") as "$".
rewrite Z2Nat.id; last word.
rewrite word.of_Z_unsigned.
iMod (readonly_alloc_1 with "nextIndex") as "$".
iMod (readonly_alloc_1 with "state") as "$".
iMod "Hargs" as "#Hargs".
iIntros (numReplies_ptr) "HnumReplies".
iMod (readonly_load with "Hclerks_sl") as (?) "Hclerks_sl2".
iDestruct (own_slice_small_sz with "Hclerks_sl2") as "%Hclerks_sz".
iIntros (replies_sl) "Hreplies_sl".
set (replyInv:=(
∃ (numReplies:u64) (reply_ptrs:list loc),
"HnumReplies" ∷ numReplies_ptr ↦[uint64T] #numReplies ∗
"Hreplies_sl" ∷ own_slice_small replies_sl ptrT 1 reply_ptrs ∗
"#Hreplies" ∷ ([∗ list] i ↦ reply_ptr ; γsrv' ∈ reply_ptrs ; γ.(s_hosts),
⌜reply_ptr = null⌝ ∨ □(∃ reply, readonly (applyAsFollowerReply.own reply_ptr reply 1) ∗
if decide (reply.(applyAsFollowerReply.err) = (U64 0)) then
is_accepted_lb γsrv' pst.(paxosState.epoch) (log ++ [(newstate, Q)])
else
True
))
)%I).
wp_apply (newlock_spec N _ replyInv with "[HnumReplies Hreplies_sl]").
iDestruct (own_slice_to_small with "Hreplies_sl") as "$".
iDestruct (big_sepL2_length with "Hclerks_rpc") as "%Hlen".
rewrite replicate_length.
rewrite lookup_replicate in H.
iIntros (replyMu) "#HreplyMuInv".
wp_apply (wp_newCond with "HreplyMuInv").
iIntros (numReplies_cond) "#HnumReplies_cond".
iMod (readonly_load with "Hclerks_sl") as (?) "Hclerks_sl2".
wp_apply (wp_forSlice (λ _, True%I) (V:=loc) with "[] [$Hclerks_sl2]").
iIntros (?? Φ) "!# (_ & %Hi_le & %Hi_lookup) HΦ".
wp_apply (wp_fork with "[]").
(* make applyAsFollower RPC and put reply in the replies list *)
(* establish is_singleClerk *)
iDestruct (big_sepL2_lookup_1_some with "Hclerks_rpc") as (?) "%Hi_conf_lookup".
iAssert (_) with "Hclerks_rpc" as "Hclerks_rpc2".
iDestruct (big_sepL2_lookup_acc with "Hclerks_rpc2") as "[#His_ck _]".
wp_apply (wp_singleClerk__applyAsFollower with "[$His_ck]").
rewrite fmap_app last_app /= //.
iIntros (reply_ptr reply) "Hreply".
wp_apply (acquire_spec with "HreplyMuInv").
iIntros "[Hlocked Hown]".
iDestruct (big_sepL2_lookup_2_some with "Hreplies") as (?) "%Hi_replies_lookup".
wp_apply (wp_SliceSet with "[$Hreplies_sl]").
iDestruct "Hreply" as "[Hreply #Hpost]".
iMod (readonly_alloc_1 with "Hreply") as "#Hreply".
wp_apply (wp_If_optional _ _ (True%I)).
wp_apply (wp_condSignal with "HnumReplies_cond").
wp_apply (release_spec with "[-]").
iDestruct (big_sepL2_insert_acc with "Hreplies") as "[_ Hreplies2]".
iDestruct ("Hreplies2" $! reply_ptr x2 with "[]") as "Hreplies3".
replace (<[int.nat i:=x2]> γ.(s_hosts)) with (γ.(s_hosts)) ; last first.
wp_apply (acquire_spec with "[$HreplyMuInv]").
iIntros "[Hlocked Hown]".
(* not enough replies, wait for cond *)
wp_apply (wp_condWait with "[-HΦ Herr]").
iIntros "[Hlocked Hown]".
(* got enough replies to stop waiting; now we need to count how many successes *)
iIntros (numSuccesses_ptr) "HnumSuccesses".
iDestruct (big_sepL2_length with "Hclerks_rpc") as %Hconf_clerk_len.
set (I:=λ (i:u64), (
∃ (W: gset nat),
"%HW_in_range" ∷ ⌜∀ s, s ∈ W → s < int.nat i⌝ ∗
"%HW_size_nooverflow" ∷ ⌜(size W) ≤ int.nat i⌝ ∗
"HnumSuccesses" ∷ numSuccesses_ptr ↦[uint64T] #(U64 (size W)) ∗
"#Hacc_lbs" ∷ ([∗ list] s ↦ γsrv' ∈ γ.(s_hosts), ⌜s ∈ W⌝ → is_accepted_lb γsrv' pst.(paxosState.epoch) (log ++ [(newstate, Q)]))
)%I).
wp_apply (wp_forSlice (V:=loc) I _ _ _ _ _ reply_ptrs with "[] [HnumSuccesses Hreplies_sl]").
iApply (big_sepL_forall).
iIntros (?? Φ) "!# (Hi & %Hi_lt & %Hi_lookup) HΦ".
iDestruct (big_sepL2_lookup_1_some with "Hreplies") as (?) "%Hi_conf_lookup".
iDestruct (big_sepL2_lookup_acc with "Hreplies") as "[#Hreply_post _]".
iDestruct "Hreply_post" as "[%Hbad|#Hreply_post]".
iDestruct "Hreply_post" as (?) "[#Hreply Hpost]".
iMod (readonly_load with "Hreply") as (?) "Hreplyq".
iEval (rewrite decide_True) in "Hpost".
iExists (W ∪ {[ int.nat i ]}).
(* prove that the new set W is still in range *)
replace (int.nat (word.add i (U64 1))) with (int.nat i + 1) by word.
rewrite elem_of_union in Hin.
destruct Hin as [Hold|Hnew].
specialize (HW_in_range s0 Hold).
rewrite elem_of_singleton in Hnew.
rewrite size_union; last first.
apply disjoint_singleton_r.
destruct (decide (int.nat i ∈ W)).
specialize (HW_in_range (int.nat i) e).
iExactEq "HnumSuccesses".
apply lookup_lt_Some in Hi_conf_lookup.
rewrite -Hconf_clerk_len Hclerks_sz in Hi_conf_lookup.
assert (Z.of_nat (size W) < int.Z clerks_sl.(Slice.sz))%Z by word.
iApply (big_sepL_impl with "Hacc_lbs").
iIntros (?? ?) "Hacc_wand".
rewrite elem_of_union in Hin.
destruct Hin as [Hold|Hnew].
rewrite elem_of_singleton in Hnew.
rewrite Hi_conf_lookup in H.
(* node i didn't accept, don't change W *)
replace (int.nat (word.add i (U64 1))) with (int.nat i + 1) by word.
specialize (HW_in_range s0 H).
(* node i didn't reply, don't change W *)
replace (int.nat (word.add i (U64 1))) with (int.nat i + 1) by word.
specialize (HW_in_range s0 H).
iIntros "[Hi Hreplies_sl]".
iDestruct (own_slice_small_sz with "Hreplies_sl") as "%Hreplies_sz".
wp_pure1_credit "Hcred1".
wp_pure1_credit "Hcred2".
(* enough acceptances to commit *)
iDestruct (big_sepL2_length with "Hreplies") as "%Hreplies_len_eq_conf".
replace (int.nat replies_sl.(Slice.sz)) with (length γ.(s_hosts)) in HW_in_range; last first.
iDestruct (establish_committed_by with "[$Hacc_lbs]") as "Hcom".
assert (2 * size W >= int.Z (u64_instance.u64.(word.mul) 2 (size W)))%Z.
rewrite word.unsigned_mul.
iMod (ghost_commit with "Hinv Hcom Hprop") as "Hlb".
(* error, too few successful applyAsFollower() RPCs *)
Lemma prefix_app_cases {A} (σ σ':list A) e:
σ' `prefix_of` σ ++ [e] →
σ' `prefix_of` σ ∨ σ' = (σ++[e]).
induction σ0 using rev_ind.
rewrite app_nil_r in Heq.
rewrite app_assoc in Heq.
apply app_inj_2 in Heq as [-> ?]; last auto.
(* This is where "helping" happens. *)
Lemma releaseFn_fact γ rel sl_ptr oldstate :
£ 1 -∗ £ 1 -∗
is_helping_inv γ -∗
own_releaseFn_internal rel γ sl_ptr oldstate -∗
own_releaseFn rel γ sl_ptr oldstate
.
iIntros "Hlc1 Hlc2 #Hinv Hwp".
iMod (ghost_var_alloc (())) as (γtok) "Htok".
set (Q := (inv escrowN (Φ #0 ∨ ghost_var γtok 1 ())%I)).
iMod (saved_prop_alloc Q DfracDiscarded) as (γghost_op) "#Hsaved"; first done.
wp_apply ("Hwp" $! _ _ _ γghost_op with "[-Hfail Htok Hlc2] [-]").
iInv "Hinv" as "HH" "Hclose".
iMod (lc_fupd_elim_later with "Hlc1 HH") as "HH".
iDestruct "HH" as (?) "(Hstate & Hghost & #HQs)".
iMod (fupd_mask_subseteq _) as "Hmask".
2: iMod "Hupd" as (?) "[Hstate2 Hupd]".
rewrite /ghostN /appN /=.
iDestruct (own_valid_2 with "Hstate Hstate2") as %Hvalid.
rewrite dfrac_agree_op_valid_L in Hvalid.
destruct Hvalid as [_ Heq].
iDestruct "Hghost" as (?) "(Hghost & %HintEq & #?)".
iMod (own_update_2 with "Hstate Hstate2") as "Hstate".
apply (dfrac_agree_update_2).
iDestruct "Hstate" as "[Hstate Hstate2]".
iMod ("Hupd" with "[] Hstate2") as "Hupd".
iAssert (|={↑escrowN}=> inv escrowN
(Φ #0 ∨ ghost_var γtok 1 ()))%I
with "[Hupd]" as "Hinv2".
iMod (inv_alloc with "[-]") as "$"; last done.
iMod (fupd_mask_subseteq (↑escrowN)) as "Hmask".
2: iMod "Hinv2" as "#HΦ_inv".
iMod ("Hclose" with "[HQs Hghost Hstate]").
iSplitL "Hstate"; last first.
repeat rewrite -sep_assoc.
iSplitR; first iPureIntro.
instantiate (1:=(log ++ [(newstate, Q)])).
do 2 rewrite fmap_app /=.
iApply big_sepL2_singleton.
apply prefix_app_cases in H as [Hprefix_of_old|Hnew].
replace (log'prefix) with (log); last first.
apply (f_equal reverse) in H0.
rewrite reverse_snoc in H0.
rewrite reverse_snoc in H0.
apply (f_equal reverse) in H2.
rewrite reverse_involutive in H2.
rewrite reverse_involutive in H2.
eassert (_ = lastEnt) as <-.
eapply (suffix_snoc_inv_1 _ _ _ log'prefix).
rewrite /get_state fmap_app last_app /=.
iIntros "* (Hlc1 & Hlc3 & Hpost)".
destruct (decide (err = U64 0)).
setoid_rewrite decide_True.
iDestruct "Hpost" as (?) "#Hghost_lb".
iInv "Hinv" as "HH" "Hclose".
iMod (lc_fupd_elim_later with "Hlc1 HH") as "HH".
iDestruct "HH" as (?) "(Hlog & Hghost & #HQs)".
iDestruct "Hghost" as (?) "(Hghost&%Hfst_eq&#Hsaved')".
iDestruct (own_valid_2 with "Hghost Hghost_lb") as %Hvalid.
rewrite mono_list_both_dfrac_valid_L in Hvalid.
destruct Hvalid as (_&σtail&Hvalid').
iDestruct (big_sepL2_length with "Hsaved'") as %Hlen.
rewrite ?fmap_length app_length in Hlen.
iAssert (_) with "Hsaved'" as "-#Hs".
iDestruct (big_sepL2_to_sepL_2 with "Hs") as "Hs".
iDestruct (big_sepL_app with "Hs") as "[Hs _]".
iDestruct (big_sepL_app with "Hs") as "[_ Hs]".
rewrite big_sepL_singleton.
iDestruct "Hs" as (?) "[%Hlookup #Hsaved2]".
destruct (log !! (length σ)) eqn:HlookupFull.
rewrite list_lookup_fmap fmap_length in Hlookup.
rewrite Nat.add_0_r HlookupFull /= in Hlookup.
assert (y1 = u); last subst.
rewrite list_lookup_fmap fmap_length in Hlookup.
rewrite Nat.add_0_r HlookupFull /= in Hlookup.
iAssert (_) with "HQs" as "HQ".
iSpecialize ("HQ" $! (take (S (length σ)) log) (take (length σ) log) _ with "[] []").
iMod ("Hclose" with "[Hghost Hlog]") as "_".
iDestruct (saved_prop_agree with "Hsaved Hsaved2") as "Hagree".
iApply (lc_fupd_add_later with "[$]").
iRewrite -"Hagree" in "HQ".
iInv "HQ" as "Hescrow" "Hclose".
iDestruct "Hescrow" as "[HΦ|>Hbad]"; last first.
iDestruct (ghost_var_valid_2 with "Htok Hbad") as %Hbad.
iMod ("Hclose" with "[$Htok]").
iMod (lc_fupd_elim_later with "Hlc2 HΦ") as "HΦ".
Lemma wp_Server__TryAcquire s γ γsrv :
{{{
is_Server s γ γsrv
}}}
Server__TryAcquire #s
{{{
(err:u64) (sl_ptr:loc) (rel:val), RET (#err, #sl_ptr, rel);
if (decide (err = 0%Z)) then
∃ sl oldstate,
sl_ptr ↦[slice.T byteT] (slice_val sl) ∗
readonly (own_slice_small sl byteT 1 oldstate) ∗
Pwf oldstate ∗
own_releaseFn rel γ sl_ptr oldstate
else
True
}}}.
wp_apply (wp_Server__TryAcquire_internal with "[$]").
iDestruct "Hpost" as "(? & ? & Hpost)".
iDestruct "Hpost" as "($ & $ & $ & H)".
iApply (releaseFn_fact with "[$] [$] [$] [$]").