-
Notifications
You must be signed in to change notification settings - Fork 1
/
proof_ms_abs_graph.v
3548 lines (3214 loc) · 158 KB
/
proof_ms_abs_graph.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
From iris.algebra Require Import auth gset gmap agree.
From iris.algebra Require Import lib.mono_list.
From iris.algebra.lib Require Import dfrac_agree.
From iris.proofmode Require Import tactics.
From gpfsl.base_logic Require Import meta_data.
From gpfsl.algebra Require Import to_agree.
From gpfsl.logic Require Import logatom atomics invariants.
From gpfsl.examples Require Import list_helper.
From gpfsl.logic Require Import repeat_loop new_delete.
From gpfsl.examples Require Import map_seq.
From gpfsl.examples.queue Require Import spec_abs_graph code_ms.
Require Import iris.prelude.options.
(** Prove that Michael-Scott Queue satisfies the logically atomic, history-based
specifications *)
#[local] Notation link := 0%nat (only parsing).
#[local] Notation data := 1%nat (only parsing).
#[local] Notation head := 0%nat (only parsing).
#[local] Notation tail := 1%nat (only parsing).
#[local] Notation event_list := (event_list qevent).
#[local] Notation graph_event := (graph_event qevent).
#[local] Notation graph := (graph qevent).
(* a logical node, implemented as the ghost name of the `AtomicPtsto` of the
location of the node. *)
Definition lnode := gname.
(* a node is a pair (η, n) of the logical name and physical location of the node *)
Definition node : Type := (lnode * loc).
Implicit Types (l: loc) (tid: thread_id) (Q : queue) (G: graph) (γ: gname) (η: lnode) (M: logView).
(* State of the link field: Null or Linked to the node (η,n) *)
Definition LinkState: Type := option node.
#[local] Notation Null := (None : LinkState).
#[local] Notation Linked η n := (Some (η, n) : LinkState).
(**** GHOST STATE CONSTRUCTION -----------------------------------------------*)
(** The CMRA & functor we need. *)
(* a persistent map of from logical nodes to event ids. *)
#[local] Notation msq_qmapUR' := (agreeMR gname event_id).
#[local] Notation msq_qmapUR := (authUR msq_qmapUR').
(* an append-only list of nodes *)
#[local] Notation msq_linkUR := (mono_listUR (leibnizO node)).
#[local] Notation msq_queueR := (prodR (prodUR msq_linkUR msq_linkUR) msq_qmapUR).
(* abstract state *)
#[local] Notation queueR := (dfrac_agreeR (leibnizO queue)).
Class msqueueG Σ := MSQueueG {
msq_graphG : inG Σ (graphR qevent);
msq_queueG : inG Σ msq_queueR;
msq_absG : inG Σ queueR;
}.
Definition msqueueΣ : gFunctors :=
#[GFunctor (graphR qevent); GFunctor msq_queueR; GFunctor queueR].
Global Instance subG_msqueueΣ {Σ} : subG msqueueΣ Σ → msqueueG Σ.
Proof. solve_inG. Qed.
(**
+ T tracks which logical node points to which enqueue event, in the form of
η |-> e, which says that η leads to the node that is enqueued as event e.
+ L tracks the linked list itself, including any node that has ever been
enqueued. L tracks the logical + physical nodes, that is a pair of (η,n)
where `n` is the physical location of the node, and `η` is the ghost name
of the atomic ptsto of `n`.
+ D is a prefix of L that only contains nodes that have been dequeued.
*)
Implicit Types (T : gmap lnode event_id) (L D : list node).
(** Namespace for our internal invariant. See `QueueInternalInv`. *)
Definition msqN (N : namespace) (q: loc) := N .@ q.
(** Decidability of whether a logical node `η`:
- has been observed by an enqueue event set `M` (indirectly through the
lnode-event_id map `T`);
- immediately follows `ηs` in L. *)
Definition enqueued_in L T (M : gset event_id) ηs : Prop :=
∃ η, η ∈ coimg T M ∧ adjacent_in ηs η (fst <$> L).
Local Instance enqueued_in_dec L T M ηs : Decision (enqueued_in L T M ηs).
Proof. intros. apply set_Exists_dec => η. apply _. Qed.
Lemma enqueued_in_choice L T (M : gset event_id) ηs :
{ η | η ∈ coimg T M ∧ adjacent_in ηs η (fst <$> L) } +
{ ∀ η, η ∈ coimg T M → adjacent_in ηs η (fst <$> L) → False }.
Proof.
case (decide (enqueued_in L T M ηs)) => [In|NIn].
- left. apply choice; [solve_decision|done].
- right. intros η Inη Sub. apply NIn. by exists η.
Qed.
(* The lnode-event_id map is in sync with the event map w.r.t. enqueue events. *)
Definition EM_equiv T (E : event_list) : Prop :=
∀ e, (∃ η, T !! η = Some e) ↔ (∃ v, ge_event <$> E !! e = Some $ Enq v).
(* Pure Coq properties of the Queue *)
Record QueueProps Q G T η s D L : Prop := mkQueueProps {
qu_no_dup : NoDup (((η, s) :: D ++ L).*1) ;
(* NoDup (CL.*2): this is implied by own_nodes *)
qu_enqueued : (* T only tracks enqueues *)
dom T ≡ list_to_set ((D ++ L).*1) ;
qu_enq_event : EM_equiv T G.(Es) ;
qu_enq_inj : (* T is also injective *)
∀ η1 η2 eid, T !! η1 = Some eid → T !! η2 = Some eid → η1 = η2 ;
qu_dequeued : (* D only contains nodes that have been dequeued *)
∀ η eid, T !! η = Some eid → ((η ∈ D.*1) ↔ eid ∈ (elements G.(so)).*1) ;
qu_enq_mo_ord :
∀ η1 η2 e1 e2, list_before ((D ++ L).*1) η1 η2 → T !! η1 = Some e1 →
T !! η2 = Some e2 → (e1 ≤ e2)%nat ;
(* Later enqueues must have observed earlier enqueues. This is a very
strong synchronization property that may not hold for all queue
implementations. *)
qu_enq_hb_ord :
∀ η1 η2 e1 e2 eV2, list_before ((D ++ L).*1) η1 η2 →
T !! η1 = Some e1 → T !! η2 = Some e2 → G.(Es) !! e2 = Some eV2 →
e1 ∈ eV2.(ge_lview) ;
qu_abs :
Forall2 (λ '(v, V) '(η, _), ∃ e eV,
T !! η = Some e ∧ G.(Es) !! e = Some eV ∧
eV.(ge_event) = Enq v ∧ eV.(ge_view).(dv_comm) = V) Q L
}.
(** The state of the Head pointer *)
(* History of Head is a contiguous list of writes, because Head is CAS-only *)
Definition toHeadHist' (start : time) (LV : list (loc * view)) : absHist :=
map_seqP start ((λ lv, (#(LitLoc lv.1),lv.2)) <$> LV).
Definition toHeadHist (start : time) D (Vs : list view) : absHist :=
toHeadHist' start (zip (snd <$> D) Vs).
Definition SyncEnqueues (E: event_list) M : Prop :=
∀ e v V Mv, e ∈ M → E !! e = Some (mkGraphEvent (Enq v) V Mv) → Mv ⊆ M.
(* A bool mask to identify which node has been dequeued *)
Definition dequeue_mask (lenD lenL : nat) : list bool :=
(repeat true lenD) ++ (repeat false lenL).
(* A next node mask to link the nodes in a list together *)
Definition next_nodes L : list LinkState :=
match L with
| [] => []
| _ :: L' => (Some <$> L') ++ [None]
end.
Lemma SyncEnqueues_mono E E' M :
set_in_bound M E → E ⊑ E' → SyncEnqueues E M → SyncEnqueues E' M.
Proof.
intros SubM SubE SE e v V Mv InM Eqe.
apply (SE e v V Mv InM), (prefix_lookup_inv _ _ _ _ Eqe); [|done].
by apply SubM.
Qed.
Lemma SyncEnqueues_union E M1 M2 :
SyncEnqueues E M1 → SyncEnqueues E M2 → SyncEnqueues E (M1 ∪ M2).
Proof.
intros SE1 SE2 e v V Mv [InM|InM]%elem_of_union.
- intros ?%(SE1 _ _ _ _ InM). set_solver.
- intros ?%(SE2 _ _ _ _ InM). set_solver.
Qed.
Lemma dequeue_mask_length (lenD lenL : nat) :
length (dequeue_mask lenD lenL) = (lenD + lenL)%nat.
Proof. by rewrite app_length 2!repeat_length. Qed.
Lemma dequeue_mask_append (lenD lenL : nat) :
dequeue_mask lenD (S lenL) = dequeue_mask lenD lenL ++ [false].
Proof. rewrite /dequeue_mask -app_assoc. f_equal. by apply repeat_cons. Qed.
Lemma dequeue_mask_lookup_Some (lenD lenL : nat) i d :
dequeue_mask lenD lenL !! i = Some d →
((i < lenD)%nat ∧ d = true ∨ (lenD ≤ i < lenD + lenL)%nat ∧ d = false).
Proof.
intros Eqi.
have LtL := lookup_lt_Some _ _ _ Eqi.
rewrite dequeue_mask_length in LtL.
destruct (Nat.lt_ge_cases i lenD) as [LtD|LeD].
- left. split; [done|].
move : Eqi. rewrite /dequeue_mask lookup_app_l.
+ by apply repeat_lookup_Some.
+ by rewrite repeat_length.
- right. split; [done|].
move : Eqi. rewrite /dequeue_mask lookup_app_r.
+ by apply repeat_lookup_Some.
+ by rewrite repeat_length.
Qed.
Lemma dequeue_mask_lookup_Some_l (lenD lenL : nat) i d :
dequeue_mask lenD lenL !! i = Some d → (i < lenD)%nat → d = true.
Proof.
intros Eqi%dequeue_mask_lookup_Some LtD.
destruct Eqi as [[]|[[]]]; [done|lia].
Qed.
Lemma dequeue_mask_lookup_Some_r (lenD lenL : nat) i d :
dequeue_mask lenD lenL !! i = Some d → (lenD ≤ i)%nat → d = false.
Proof.
intros Eqi%dequeue_mask_lookup_Some LeD.
destruct Eqi as [[]|[[]]]; [lia|done].
Qed.
Lemma dequeue_mask_lookup_Some' (lenD lenL : nat) i d :
dequeue_mask lenD lenL !! i = Some d ↔
(((i < lenD)%nat ∧ d = true ∨ (lenD ≤ i < lenD + lenL)%nat ∧ d = false)).
Proof.
split; [apply dequeue_mask_lookup_Some|]. intros Eq.
destruct (lookup_lt_is_Some_2 (dequeue_mask lenD lenL) i) as [d' Eqd'].
{ rewrite dequeue_mask_length. lia. }
rewrite Eqd'. f_equal.
destruct Eq as [[]|[[]]]; subst d.
- eapply dequeue_mask_lookup_Some_l; eauto.
- eapply dequeue_mask_lookup_Some_r; eauto.
Qed.
Lemma next_nodes_lookup_Some L i n :
next_nodes L !! i = Some (Some n) ↔ L !! (i+1)%nat = Some n.
Proof.
destruct L as [|s L]; simpl; [done|].
rewrite Nat.add_1_r /=.
case (decide (i < length (Some <$> L))%nat) => EqL.
- rewrite lookup_app_l // list_lookup_fmap.
destruct (L !! i); [simpl; naive_solver|done].
- apply Nat.nlt_ge in EqL.
rewrite lookup_app_r; [|done].
rewrite (lookup_ge_None_2 L); [|by rewrite fmap_length in EqL].
split; [|done].
by intros ?%elem_of_list_lookup_2%elem_of_list_singleton.
Qed.
Lemma next_nodes_lookup_None L i :
next_nodes L !! i = Some None → (0 < length L)%nat ∧ i = (length L - 1)%nat.
Proof.
rewrite /next_nodes. destruct L; [done|].
rewrite /= Nat.sub_0_r. intros Eqi. split; [lia|].
move : (lookup_lt_Some _ _ _ Eqi).
rewrite app_length /= fmap_length Nat.add_1_r => /Nat.lt_succ_r Lti.
case (decide (length L ≤ i)%nat) => [Le|/Nat.nle_gt Lt].
- by apply : anti_symm.
- exfalso.
rewrite lookup_app_l in Eqi; [|by rewrite fmap_length].
move : Eqi. rewrite list_lookup_fmap.
by apply lookup_lt_is_Some_2 in Lt as [? ->].
Qed.
Lemma next_nodes_app_2 L x y :
∃ (L' : list LinkState),
next_nodes ((L ++ [x]) ++ [y]) = (L' ++ [Some y]) ++ [None] ∧
next_nodes (L ++ [x]) = L' ++ [None] ∧
length L = length L'.
Proof.
rewrite /next_nodes. destruct L as [|z L]; simpl.
- exists []. by simplify_list_eq.
- exists (Some <$> L ++ [x]). simplify_list_eq.
by rewrite app_length /= fmap_length Nat.add_1_r.
Qed.
Lemma infos_next_lookup L (dms : list bool) d i ηs :
let infos := zip (next_nodes L) dms in
infos !! i = Some (ηs, d) ->
next_nodes L !! i = Some ηs ∧
dms !! i = Some d ∧
if ηs is Some ηn' then L !! (i + 1)%nat = Some ηn' else True.
Proof.
intros infos Eq.
apply lookup_zip_with_Some in Eq as (ηs'&d'&Eq&Eq1&Eq2). inversion Eq.
subst ηs' d'. do 2 (split; [done|]).
destruct ηs as [ηn'|]; [|done].
by apply next_nodes_lookup_Some in Eq1.
Qed.
Lemma infos_dequeue ηs s D L η n :
let CL := (ηs, s) :: D ++ (η, n) :: L in
let lenD := length D in
let lenL := S (length ((η, n) :: L)) in
let lenD' := length (D ++ [(η,n)]) in
let lenL' := S (length L) in
let infos := zip (next_nodes CL) (dequeue_mask lenD lenL) in
let infos' := zip (next_nodes CL) (dequeue_mask lenD' lenL') in
∀ (EqL: length CL = length infos),
(∃ η' n', CL !! lenD = Some (η', n')) ∧
infos !! lenD = Some (Some (η, n), false) ∧
infos' = <[lenD:=(Some (η, n), true)]> infos.
Proof.
intros.
have EqLD' : (lenD' + lenL' = lenD + lenL)%nat.
{ rewrite /lenD' /lenL' /lenD /lenL app_length /=. clear.
by rewrite Nat.add_1_r Nat.add_succ_comm. }
have EqLI: length infos = length infos'.
{ rewrite 2!zip_with_length. f_equal. by rewrite 2!dequeue_mask_length. }
have EqL' : length CL = length infos' by rewrite EqL.
have Eqη : CL !! length ((ηs, s) :: D) = Some (η,n).
{ rewrite /CL (lookup_app_r (_::_)); [|done]. by rewrite Nat.sub_diag. }
have LtLCL: (lenD < length CL)%nat.
{ rewrite (app_length (_::_)) /= -Nat.add_succ_r.
apply Nat.lt_add_pos_r. lia. }
destruct (lookup_lt_is_Some_2 _ _ LtLCL) as [[η' n'] Eq'].
split. { by eauto. }
destruct (lookup_lt_is_Some_2 infos lenD) as [[ηn' d] Eq].
{ by rewrite -EqL. }
destruct (infos_next_lookup _ _ _ _ _ Eq) as (EqNN & DQM & Eqηn').
destruct ηn' as [ηn'|]; last first.
{ apply next_nodes_lookup_None in EqNN as [? EqN].
exfalso. move : EqN. rewrite /CL (app_length (_::_)) /=. lia. }
have ?: ηn' = (η,n).
{ rewrite /lenD cons_length in Eqη. rewrite Nat.add_1_r Eqη in Eqηn'.
by inversion Eqηn'. } subst ηn'.
have ?: d = false.
{ by apply (dequeue_mask_lookup_Some_r _ _ _ _ DQM). } subst d.
split; [done|].
have LtD: (lenD < lenD')%nat. { rewrite /lenD /lenD' app_length /=. lia. }
have DQM' : dequeue_mask lenD' lenL' !! lenD = Some true.
{ destruct (lookup_lt_is_Some_2 (dequeue_mask lenD' lenL') lenD) as [d' Eqd'].
- rewrite dequeue_mask_length. lia.
- by rewrite -(dequeue_mask_lookup_Some_l _ _ _ _ Eqd'). }
have EqIN' : infos' !! lenD = Some (Some (η, n), true).
{ by rewrite lookup_zip_with EqNN DQM' /=. }
apply list_eq => i.
case (decide (i = lenD)) => [->|NEq].
{ rewrite list_lookup_insert; [done|by rewrite -EqL]. }
rewrite list_lookup_insert_ne; [|done].
destruct (infos !! i) as [ηi|] eqn:Eqηi; last first.
{ apply lookup_ge_None. apply lookup_ge_None in Eqηi. by rewrite -EqLI. }
apply lookup_zip_with_Some.
apply lookup_zip_with_Some in Eqηi as (ηs' & d' & -> & EqN & EqD).
exists ηs', d'. split; [done|]. split ;[done|].
apply dequeue_mask_lookup_Some'.
apply dequeue_mask_lookup_Some in EqD as [[Lti ?]|[[Lei Lti] ?]].
- left. split; [|done]. rewrite /lenD' app_length /=. lia.
- right. split; [|done]. split; [|by rewrite EqLD'].
rewrite /lenD' app_length /=. lia.
Qed.
Lemma toHeadHist_lookup_Some DL Vs t0 t v V :
(toHeadHist t0 DL Vs) !! t = Some (v, V) ↔
(t0 ≤ t)%positive
∧ Vs !! (Pos.to_nat t - Pos.to_nat t0)%nat = Some V
∧ ∃ η (l : loc), v = #l ∧ DL !! (Pos.to_nat t - Pos.to_nat t0)%nat = Some (η, l).
Proof.
rewrite lookup_map_seqP_Some. f_equiv.
rewrite list_lookup_fmap fmap_Some.
setoid_rewrite lookup_zip_with_Some.
setoid_rewrite list_lookup_fmap.
setoid_rewrite fmap_Some. split.
- intros [[] [(? & ? & ? & ([] & ? & ?) & ?) ?]]. simpl in *. simplify_eq.
naive_solver.
- intros [? (η&l&?&?)]. simplify_eq.
exists (l,V). naive_solver.
Qed.
Lemma toHeadHist_lookup_None DL Vs t0 t :
length DL = length Vs →
(toHeadHist t0 DL Vs) !! t = None ↔
(t < t0)%positive ∨ (t0 +p (length DL) ≤ t)%positive.
Proof.
intros EqL.
by rewrite lookup_map_seqP_None fmap_length zip_with_length_l_eq fmap_length.
Qed.
Lemma toHeadHist_lookup_Some_is_comparable_loc t0 DL Vs t v l1 :
fst <$> (toHeadHist t0 DL Vs) !! t = Some v →
∃ vl : lit, v = #vl ∧ lit_comparable l1 vl.
Proof.
destruct ((toHeadHist t0 DL Vs) !! t) as [[v' V]|] eqn:Eqv; simpl; [|done].
intros. simplify_eq.
apply toHeadHist_lookup_Some in Eqv as (_ & _ & η & l & ? & _).
subst v. exists l. split; [done|constructor].
Qed.
Lemma toHeadHist_insert t0 L Vs t V η (n : loc) :
(Pos.to_nat t - Pos.to_nat t0)%nat = length L →
(1 ≤ length L)%nat →
length L = length Vs →
<[t := (#n, V)]>(toHeadHist t0 L Vs) = toHeadHist t0 (L ++ [(η, n)]) (Vs ++ [V]).
Proof.
intros Eq ? EqL. apply map_eq.
intros i. case (decide (i = t)) => [->|?].
- rewrite lookup_insert. symmetry.
apply toHeadHist_lookup_Some. split; [lia|].
rewrite Eq !lookup_app_r EqL // Nat.sub_diag /=. naive_solver.
- rewrite lookup_insert_ne; [|done].
destruct (toHeadHist t0 L Vs !! i) as [[vi Vi]|] eqn:Eqi; rewrite Eqi; symmetry.
+ apply toHeadHist_lookup_Some in Eqi as (? & Eq1 & η' & n' & -> & Eq2).
apply toHeadHist_lookup_Some. split; [done|].
rewrite (lookup_app_l_Some _ _ _ _ Eq1) (lookup_app_l_Some _ _ _ _ Eq2) /=.
naive_solver.
+ have ?: length (L ++ [(η, n)]) = length (Vs ++ [V])
by rewrite !app_length /= EqL.
apply toHeadHist_lookup_None; [done|].
apply toHeadHist_lookup_None in Eqi; [|done].
destruct Eqi as [?|Eqi]; [by left|right].
rewrite app_length /=. move : Eqi.
rewrite Nat.add_1_r pos_add_succ_r_2.
rewrite (_: t0 +p length L = t); [lia|]. rewrite -Eq /pos_add_nat; lia.
Qed.
(** * Ghost assertions *)
#[local] Notation LTGhost a := ((ε, a) : msq_queueR).
#[local] Notation LEGhost a := (((a, ε), ε) : msq_queueR).
#[local] Notation LDGhost a := (((ε, a), ε) : msq_queueR).
Section ghost.
Context `{!inG Σ msq_queueR, !inG Σ queueR}.
#[local] Notation iProp := (iProp Σ).
#[local] Notation vProp := (vProp Σ).
(* The logical snapshots of the queue *)
Definition LTM_snap γq T : iProp := own γq (LTGhost (◯ (to_agreeM T))).
Definition LTM_snapv γq T : vProp := ⎡ LTM_snap γq T ⎤.
Definition LTM_ssnap γq η e : iProp := LTM_snap γq {[η := e]}.
Definition LTM_ssnapv γq η e : vProp := ⎡ LTM_ssnap γq η e ⎤.
Definition LEL_snap γq L : iProp :=
own γq (LEGhost (◯ML (L : listO (leibnizO node)))).
Definition LEL_snapv γq L : vProp := ⎡ LEL_snap γq L ⎤.
Definition LDL_snap γq D : iProp :=
own γq (LDGhost (◯ML (D : listO (leibnizO node)))).
Definition LDL_snapv γq D : vProp := ⎡ LDL_snap γq D ⎤.
(* LTM_master and LEL_master track the enqueues *)
Definition LTM_auth T : msq_qmapUR := ● (to_agreeM T) ⋅ ◯ (to_agreeM T).
Definition LTM_master γq T : iProp := own γq (LTGhost (LTM_auth T)).
Definition LTM_masterv γq T : vProp := ⎡ LTM_master γq T ⎤.
Definition LEL_master γq L : iProp :=
own γq (LEGhost (●ML ((L : listO (leibnizO node))))).
Definition LEL_masterv γq L : vProp := ⎡ LEL_master γq L ⎤.
(* LDL_master track the dequeues *)
Definition LDL_master γq D : iProp :=
own γq (LDGhost (●ML ((D : listO (leibnizO node))))).
Definition LDL_masterv γq D : vProp := ⎡ LDL_master γq D ⎤.
Definition Queue γa q Q : iProp := own γa (to_frac_agree q (Q : leibnizO queue)).
Definition Queuev γa q Q : vProp := ⎡ Queue γa q Q ⎤.
End ghost.
(** * THE INVARIANT AND LOCAL ASSERTIONS -------------------------------------*)
Section Interp.
Context `{!noprolG Σ, !msqueueG Σ, !atomicG Σ}.
Local Existing Instances msq_graphG msq_queueG msq_absG.
#[local] Notation iProp := (iProp Σ).
#[local] Notation vProp := (vProp Σ).
(** * LOCAL OBSERVATIONS ----------------------------------------*)
(* Asserts the observation of the enqueue event `eid` for value `v`. *)
Definition seen_enqueued_val E eid v V : vProp :=
∃ eV : graph_event,
⌜ eV.(ge_event) = Enq v ∧ eV.(ge_view).(dv_comm) = V ∧ SyncEnqueues E eV.(ge_lview) ⌝ ∗
SeenEvent E eid eV.
(* Physical observation of the Link field. *)
Definition link_val η l V (v : lit) : vProp :=
∃ V' ζl, ⌜ V' ⊑ V ∧ ∃ t, ζl !! t = Some (#v, V') ⌝ ∧ l sn⊒{η} ζl.
(* Physical observation of Null for Link *)
Definition link_val_0 η l : vProp :=
∃ V ζl, ⌜ ∃ t, ζl !! t = Some (#0, V) ⌝ ∧ l sn⊒{η} ζl (* ∗ ⊒V *).
(* Observed that η'
- has been enqueued with eid, v', and V,
- and immediately follows η in L. *)
Definition seen_enqueued E T L η V eid η' v' : vProp :=
⌜adjacent_in η η' (fst <$> L) ∧ T !! η' = Some eid ⌝ ∗
seen_enqueued_val E eid v' V.
(* Observed that (η',l')
- has been enqueued with eid, v', and V,
- and immediately follows (η,l) in L
- and has been stored physically in (η,l). *)
Definition SeenLinked E T L η l V eid η' l' v' : vProp :=
seen_enqueued E T L η V eid η' v' ∗ ⌜ (η,l) ∈ L ∧ (η',l') ∈ L ⌝ ∗ link_val η l V l'.
#[global] Instance SeenLinked_persistent E T L η l V eid η' l' v' :
Persistent (SeenLinked E T L η l V eid η' l' v') := _.
(* - If η is head of L (sentinnel node), then logically observes that η ∈ L.
- Otherwise, physically observes some enqueue event eid for η, and logically
observes that η immediately follows some η' in L. *)
Definition SeenEnqueuedLink E T L η V : vProp :=
match L with
| [] => False
| (ηs, _) :: _ =>
if decide (ηs = η) then (⊒V)%I
else (∃ eid η' v, seen_enqueued E T L η' V eid η v)%I
end.
#[global] Instance SeenEnqueuedLink_persistent E T L η V :
Persistent (SeenEnqueuedLink E T L η V).
Proof. destruct L as [|[]]; [apply _|]. simpl. case decide => ?; apply _. Qed.
#[global] Instance SeenEnqueuedLink_timeless E T L η V :
Timeless (SeenEnqueuedLink E T L η V).
Proof. destruct L as [|[]]; [apply _|]. simpl. case decide => ?; apply _. Qed.
Definition SeenEnqueuedLink_val E T L η l : vProp :=
∃ V, SeenEnqueuedLink E T L η V ∗ ⌜(η, l) ∈ L⌝ ∗ link_val η l V 0.
#[global] Instance SeenEnqueuedLink_val_persistent E T L η l :
Persistent (SeenEnqueuedLink_val E T L η l) := _.
#[global] Instance SeenEnqueuedLink_val_timeless E T L η l :
Timeless (SeenEnqueuedLink_val E T L η l) := _.
(** Observation of an event set `M`: any enqueue event should have been
observed as some node being linked in the list. *)
(* TODO: we may also need observation for dequeue event. *)
Definition SeenLinked_logview
L T E M : vProp :=
(* Define what it means to have observed the logical view M *)
∀ e v V Mv, ⌜ e ∈ M ∧ E !! e = Some (mkGraphEvent (Enq v) V Mv) ⌝ →
∃ η' l' η l,
(* proof of the observation of the enqueue *)
SeenLinked E T L η' l' V.(dv_comm) e η l v.
(* For any event e with physical view V and logical view Mv, V should support
the observation of Mv for enqueue events. *)
Definition QueueViews L T E : vProp :=
∀ e ev V Mv, ⌜ E !! e = Some (mkGraphEvent ev V Mv) ⌝ →
(* the physical view V observed the logical view Mv *)
@{V.(dv_comm)} SeenLinked_logview L T E Mv.
#[global] Instance QueueViews_persistent L T E :
Persistent (QueueViews L T E) := _.
#[global] Instance QueueViews_objective L T E :
Objective (QueueViews L T E) := _.
(**** RESOURCES OF NODES -----------------------------------------------------*)
(*** History of the Link field, and resources attached to it.
- If Link is Null, the history is the singleton of ζ0.
- If Link is Linked η1 l1, then the history is ζ0 appended (at t0+1) with
(η1, l1). The resources attached are:
+ an observation that (η1,l1) has been enqueued with eiq, v1, V
+ (η1,l1) has been initialized to Null
+ if it has not been dequeued, the non-atomic ptsto of its Data field.
*)
Definition LinkRes E T η l (deq : bool) (s : LinkState) t0 V0 ζ : vProp :=
let ζ0 : absHist := {[t0 := (#0, V0)]} in
match s with
(* Null *)
| None => ⌜ζ = ζ0⌝
(* Linked η1 l1 *)
| Some (η1,l1) =>
∃ V eid (v1 : Z),
(* CAS only: there are only two events t0 and t0 + 1 *)
⌜ζ = <[(t0 + 1)%positive := (#l1, V)]> ζ0⌝
(* The following is basically
[SeenLinked em L η l V eid η1 l1 ∗ link_val η1 l1 V 0]
WITHOUT (1) the part about L and (2) the part [link_val η l V l1].
- (2) is already acquired when the reader of [l] acquires this state
[Linked η1 l1]
- (1) is set up in the full invariant [QueueInternalInv], where (η1,l1)
here immediately follows (η, l) in the authoritative L. *)
∗ ⌜ T !! η1 = Some eid ⌝
∗ @{V}(seen_enqueued_val E eid v1 V
∗ link_val η1 l1 V 0
∗ if deq then emp else (l1 >> data) ↦ #v1)
end.
(* The full resource for a node also includes the AtomicPtsto of the Link field. *)
Definition Link E T η l (deq : bool) (s : LinkState) : vProp :=
∃ t0 V0 ζ, l at↦{η} ζ ∗ LinkRes E T η l deq s t0 V0 ζ.
#[global] Instance LinkRes_timeless E T η l d s t0 V0 ζ :
Timeless (LinkRes E T η l d s t0 V0 ζ).
Proof.
rewrite /LinkRes. destruct s; [|apply _]. destruct n. destruct d; apply _.
Qed.
#[global] Instance LinkRes_persistent E T η l s t0 V0 ζ :
Persistent (LinkRes E T η l true s t0 V0 ζ).
Proof. rewrite /LinkRes. destruct s; [|apply _]. destruct n. apply _. Qed.
#[global] Instance LinkRes_objective E T η l d s t0 V0 ζ :
Objective (LinkRes E T η l d s t0 V0 ζ).
Proof. rewrite /LinkRes. destruct s; [|apply _]. destruct n. apply _. Qed.
#[global] Instance Link_timeless E T η l d s : Timeless (Link E T η l d s) := _.
(** Setting up the list *)
(* All nodes of the list CL *)
Definition own_nodes E T η0 s0 (D L : list node) : vProp :=
let CL := (η0, s0) :: D ++ L in
let lenD := length D in let lenL := S (length L) in
let infos := zip (next_nodes CL) (dequeue_mask lenD lenL) in
[∗ list] ηl ; ld ∈ CL ; infos,
let '(η, l) := ηl in let '(ηl', d) := ld in Link E T η l d ηl'.
(*** THE INVARIANT -----------------------------------------------------------*)
Definition SeenDequeueds γg γ D : vProp :=
LDL_snapv γ D ∗
∃ G T (M : list event_id),
graph_snap γg G (list_to_set M) ∗
LTM_snapv γ T ∗
[∗ list] η;d ∈ D.*1;M, ⌜ ∃ e : event_id, T !! η = Some e ∧ (e, d) ∈ G.(com) ⌝ .
(* Resources of Head: observation of the nodes, as Head's history only contains
locations that have been dequeued. *)
Definition Head γg γ E T D (Vs : list view) : vProp :=
[∗ list] k ↦ ηx;V ∈ D;Vs,
@{V} (SeenEnqueuedLink_val E T D ηx.1 ηx.2 ∗
if k is O then emp else ∃ D', SeenDequeueds γg γ (D' ++ [ηx])).
#[global] Instance Head_persistent γg γ E T D Vs : Persistent (Head γg γ E T D Vs).
Proof. apply big_sepL2_persistent. intros [|]; apply _. Qed.
#[global] Instance Head_timeless γg γ E T D Vs : Timeless (Head γg γ E T D Vs).
Proof. apply big_sepL2_timeless. intros [|]; apply _. Qed.
(* History and resource of the Tail pointer *)
(* The history of Tail has arbitrary shape, because it can contain racing writes.
The only useful information is that it only contains locations, and that each
write comes with an observation of that location. *)
(* This implementation allows Tail to be lagging behind the actual Tail.
If we want the Tail to point to the actual Tail, we also need to use CASes
only for the Tail. *)
Definition Tail E T L (ζl : absHist) : vProp :=
∀ t v V, ⌜ζl !! t = Some (v, V)⌝ →
∃ x, ⌜v = #(LitLoc x)⌝ ∗ ∃ η, @{V} SeenEnqueuedLink_val E T L η x.
#[global] Instance Tail_persistent E T L ζ : Persistent (Tail E T L ζ) := _.
#[global] Instance Tail_timeless E T L ζ : Timeless (Tail E T L ζ) := _.
(*** QueueInv assertion, specific to this implementation--------------------- *)
(* Locs of the Queue: Head, Tail, and nodes *)
Definition QueueLocs γg γ q E γh γl η0 s0 D L T : vProp :=
let CL := (η0, s0) :: D ++ L in
let DL := (η0, s0) :: D in
(* Head *)
(∃ t0 Vs, (q >> head) at↦{γh} (toHeadHist t0 DL Vs) ∗ Head γg γ E T DL Vs)
(* Tail *)
∗ (∃ ζl, (q >> tail) at↦{γl} ζl ∗ Tail E T CL ζl)
(* Nodes *)
∗ own_nodes E T η0 s0 D L
.
(** Internal invariant, specific to this implementation. *)
Definition QueueInv_no_exist γg q Q G γ γh γl η0 s0 D L T : vProp :=
(* (η0, s0) : sentinnel node, D: dequeued nodes, L: remaining nodes *)
let CL := (η0, s0) :: D ++ L in
let DL := (η0, s0) :: D in
(* LEL_master tracks the complete list *)
LEL_masterv γ CL ∗
(* LDL_master tracks the dequeued list *)
LDL_masterv γ D ∗
(* LTM_master connects the logical enqueues and the event graph *)
LTM_masterv γ T ∗
⌜ QueueProps Q G T η0 s0 D L ⌝
(* Observations of queue events' views *)
∗ QueueViews CL T G.(Es)
(* Locs of the queue *)
∗ ∃ Vb, @{Vb} QueueLocs γg γ q G.(Es) γh γl η0 s0 D L T.
#[global] Instance own_nodes_timeless E T η s D L :
Timeless (own_nodes E T η s D L).
Proof. apply big_sepL2_timeless => _ [??] [??]. apply _. Qed.
#[global] Instance QueueInv_no_exist_timeless γg q Q G γ γh γl η0 s0 D L T :
Timeless (QueueInv_no_exist γg q Q G γ γh γl η0 s0 D L T) := _.
Definition QueueBaseInv γ γh γl γg q Q G : vProp :=
∃ η0 s0 D L T, QueueInv_no_exist γg q Q G γ γh γl η0 s0 D L T.
(* Only share the ghost state with the client. *)
Definition QueueInv γg (q : loc) Q G : vProp :=
⌜ StrongQueueConsistent G ⌝ ∗ graph_master γg (1/2) G
∗ (∃ γa : gname, meta q nroot γa ∗ Queuev γa (1/2) Q).
#[global] Instance QueueInv_objective γg q Q G : Objective (QueueInv γg q Q G) := _.
(* Our internal invariant keeps all the physical resources, as well as enough
ghost resources (`QueueInv`) to maintain agreement with the client. *)
Definition QueueInternalInv γ γh γl γg q : vProp :=
∃ Q G, QueueInv γg q Q G ∗ QueueBaseInv γ γh γl γg q Q G.
#[global] Instance QueueInternalInv_objective γ γh γl γg q :
Objective (QueueInternalInv γ γh γl γg q) := _.
#[global] Instance QueueInternalInv_timeless γ γh γl γg q :
Timeless (QueueInternalInv γ γh γl γg q) := _.
(*** QueueLocal assertion, specific to this implementation------------------- *)
Definition HeadSeen q γh D : vProp :=
∃ t0 Vs, (q >> head) sn⊒{γh} (toHeadHist t0 D Vs)
∗ [∗ list] ηx ∈ D, link_val_0 ηx.1 ηx.2.
Global Instance HeadSeen_persistent q γh D : Persistent (HeadSeen q γh D) := _.
Definition QueueSeen γ γh γl q G M : vProp :=
∃ ηs s D L D' T, ⌜ D' ⊑ D ⌝
∗ HeadSeen q γh ((ηs,s) :: D')
∗ (∃ ζl, (q >> tail) sn⊒{γl} ζl)
∗ let CL := (ηs,s) :: D ++ L in
LEL_snapv γ CL ∗ LDL_snapv γ D ∗ LTM_snapv γ T
(* some of QueueProps, only here for convenience *)
∗ ⌜ NoDup CL.*1
∧ dom T ≡ list_to_set ((D ++ L).*1)
∧ EM_equiv T G.(Es)
∧ (∀ η1 η2 eid, T !! η1 = Some eid → T !! η2 = Some eid → η1 = η2)
∧ (∀ η eid, T !! η = Some eid → (η ∈ D.*1 ↔ eid ∈ (elements G.(so)).*1))
∧ SyncEnqueues G.(Es) M ⌝
∗ SeenLinked_logview CL T G.(Es) M
∗ SeenLogview G.(Es) M
.
#[global] Instance QueueSeen_persistent γ γh γl q G M :
Persistent (QueueSeen γ γh γl q G M) := _.
Definition InternInv N γ γh γl γg q := inv (msqN N q) (QueueInternalInv γ γh γl γg q).
Definition QueueLocal N γg q G logV : vProp :=
graph_snap γg G logV
∗ ∃ γ γh γl, QueueSeen γ γh γl q G logV
∗ InternInv N γ γh γl γg q.
#[global] Instance QueueLocal_persistent N γg q G M :
Persistent (QueueLocal N γg q G M) := _.
(*** Lots and lots of properties for the local assertions and invariants.-----*)
Lemma link_val_0_0 η l V : link_val η l V 0 ⊢ link_val_0 η l.
Proof. iDestruct 1 as (?? [? Eq]) "SN". iExists _, _. iFrame (Eq) "SN". Qed.
(* Various seen enqueued observations. *)
Lemma seen_enqueued_val_sync_logview E e v V eV :
E !! e = Some eV →
seen_enqueued_val E e v V ⊢ @{V} SeenLogview E eV.(ge_lview).
Proof. iDestruct 1 as (? [? [??]]) "(% & ? & _)". simplify_eq. by iFrame. Qed.
Lemma SeenLinked_seen_logview E T L η' l' V e η l v eV :
E !! e = Some eV →
SeenLinked E T L η' l' V e η l v ⊢ @{V} SeenLogview E eV.(ge_lview).
Proof.
iIntros (EqE) "[[_ H] _]". by iApply (seen_enqueued_val_sync_logview with "H").
Qed.
Lemma seen_enqueued_val_seen_view E eid v V :
seen_enqueued_val E eid v V ⊢ ⊒V.
Proof. iDestruct 1 as (? [_ [Eq ?]]) "(_ & _ & ?)". by rewrite Eq. Qed.
Lemma seen_enqueued_seen_view E T L η V eid η' v' :
seen_enqueued E T L η V eid η' v' ⊢ ⊒V.
Proof. iDestruct 1 as "[_ ?]". by rewrite seen_enqueued_val_seen_view. Qed.
Lemma seen_enqueued_val_map_mono E E' V eid v (SUB: E ⊑ E') :
seen_enqueued_val E eid v V ⊢ seen_enqueued_val E' eid v V.
Proof.
iDestruct 1 as (eV (?&?&?)) "SE".
iExists eV. iDestruct (SeenEvent_mono with "SE") as "#$"; [done|].
iDestruct "SE" as "(_ & SL & _)". rewrite SeenLogview_closed.
iDestruct "SL" as %Sub. iPureIntro. do 2 (split; [done|]).
eapply SyncEnqueues_mono; eauto.
Qed.
Lemma seen_enqueued_list_mono E T L L' η V eid η' v' (SUB: L ⊑ L') :
seen_enqueued E T L η V eid η' v' ⊢ seen_enqueued E T L' η V eid η' v'.
Proof. iIntros "[? $]". by rewrite SUB. Qed.
Lemma seen_enqueued_emap_mono E E' T L η V eid η' v' (SUB: E ⊑ E') :
seen_enqueued E T L η V eid η' v' ⊢ seen_enqueued E' T L η V eid η' v'.
Proof. iIntros "[$ ?]". by rewrite seen_enqueued_val_map_mono. Qed.
Lemma seen_enqueued_tmap_mono E T T' L η V eid η' v' (SUB: T ⊆ T') :
seen_enqueued E T L η V eid η' v' ⊢ seen_enqueued E T' L η V eid η' v'.
Proof. iIntros "[[%%] $] !%". split; [done|]. by eapply lookup_weaken. Qed.
Lemma seen_enqueued_mono E E' T T' L L' η V eid η' v'
(SUB1: E ⊑ E') (SUB2 : T ⊆ T') (SUB3: L ⊑ L') :
seen_enqueued E T L η V eid η' v' ⊢ seen_enqueued E' T' L' η V eid η' v'.
Proof.
rewrite seen_enqueued_emap_mono // seen_enqueued_tmap_mono //.
by apply seen_enqueued_list_mono.
Qed.
Lemma SeenLinked_list_mono E T L L' η l V eid η' l' v' (SUB: L ⊑ L') :
SeenLinked E T L η l V eid η' l' v' ⊢ SeenLinked E T L' η l V eid η' l' v'.
Proof.
iIntros "(? & ? & $)". rewrite seen_enqueued_list_mono // SUB. by iFrame.
Qed.
Lemma SeenLinked_emap_mono E E' T L η l V eid η' l' v' (SUB: E ⊑ E') :
SeenLinked E T L η l V eid η' l' v' ⊢ SeenLinked E' T L η l V eid η' l' v'.
Proof. iIntros "[? $]". by rewrite seen_enqueued_emap_mono. Qed.
Lemma SeenLinked_tmap_mono E T T' L η l V eid η' l' v' (SUB: T ⊆ T') :
SeenLinked E T L η l V eid η' l' v' ⊢ SeenLinked E T' L η l V eid η' l' v'.
Proof. iIntros "[? $]". by rewrite seen_enqueued_tmap_mono. Qed.
Lemma SeenLinked_mono E E' T T' L L' η l V eid η' l' v'
(SUB1: E ⊑ E') (SUB2: T ⊆ T') (SUB3: L ⊑ L') :
SeenLinked E T L η l V eid η' l' v' ⊢ SeenLinked E' T' L' η l V eid η' l' v'.
Proof. rewrite SeenLinked_emap_mono // SeenLinked_tmap_mono // SeenLinked_list_mono //. Qed.
Lemma SeenEnqueuedLink_seen_view E T L η V :
SeenEnqueuedLink E T L η V ⊢ ⊒V.
Proof.
destruct L as [|[]]; simpl.
- by iDestruct 1 as %?.
- case decide => ?; [done|].
iDestruct 1 as (???) "?". by rewrite seen_enqueued_seen_view.
Qed.
Lemma SeenEnqueuedLink_mono E E' T T' L L' η V :
E ⊑ E' → T ⊆ T' → L ⊑ L' →
SeenEnqueuedLink E T L η V ⊢ SeenEnqueuedLink E' T' L' η V.
Proof.
iIntros (S1 S2 S3) "SE". rewrite /SeenEnqueuedLink.
destruct L as [|[ηs s] L]; [done|].
destruct L' as [|n' L']. { by apply prefix_nil_not in S3. }
have ?:= prefix_cons_inv_1 _ _ _ _ S3. subst n'.
have ?:= prefix_cons_inv_2 _ _ _ _ S3.
case decide => ?; [done|].
iDestruct "SE" as (eid η' v) "SE".
iExists eid, η', v. by iApply (seen_enqueued_mono with "SE").
Qed.
Lemma SeenEnqueuedLink_val_mono E E' T T' L L' η l :
E ⊑ E' → T ⊆ T' → L ⊑ L' →
SeenEnqueuedLink_val E T L η l ⊢ SeenEnqueuedLink_val E' T' L' η l.
Proof.
iIntros (S1 S2 S3). iDestruct 1 as (V) "(SE & % & SN)".
iExists V. rewrite SeenEnqueuedLink_mono //. iFrame.
iPureIntro. by eapply elem_of_list_prefix.
Qed.
Lemma SeenLinked_logview_mono L L' T T' E E' M :
L ⊑ L' → T ⊆ T' → E ⊑ E' → set_in_bound M E →
SeenLinked_logview L T E M ⊢ SeenLinked_logview L' T' E' M.
Proof.
iIntros (SL ST SE InD) "SL". iIntros (e v V M' [InM Eqe]).
iDestruct ("SL" $! e v V with "[%]") as (η' l' η l) "Seen".
{ split; [done|]. specialize (InD _ InM). by eapply prefix_lookup_inv. }
iExists η', l', η, l. by iApply (SeenLinked_mono with "Seen").
Qed.
(* Link resources *)
Lemma LinkRes_unfold E T η l d s t0 V0 ζ :
LinkRes E T η l d s t0 V0 ζ ⊣⊢
⌜ s = Null ∧ ζ = {[ t0 := (#0, V0)]} ⌝
∨ ∃ η1 l1 V1 eid v1,
⌜ s = Linked η1 l1
∧ ζ = <[(t0 + 1)%positive:=(#l1, V1)]> {[ t0 := (#0, V0)]}
∧ T !! η1 = Some eid ⌝
∗ @{V1} (seen_enqueued_val E eid v1 V1
∗ link_val η1 l1 V1 0
∗ (if d then emp else (l1 >> 1) ↦{1} #v1)).
Proof.
rewrite /LinkRes. destruct s as [[η1 l1]|]; iSplit.
- iDestruct 1 as (V1 eid v1 F1 F2) "?".
iRight. iExists η1, l1, V1, eid, v1. eauto.
- iIntros "[[% _]|H]"; [done|]. iDestruct "H" as (η2 l2 V1 eid v1 (?&?&?)) "?".
simplify_eq. iExists V1, eid, v1. by eauto.
- iIntros (?). by iLeft.
- iIntros "[[%%]|H]"; [done|]. by iDestruct "H" as (????? [? _]) "_".
Qed.
Lemma LinkRes_case_pure E T η l d s t0 V0 ζ :
LinkRes E T η l d s t0 V0 ζ ⊢
⌜ s = Null ∧ ζ = {[ t0 := (#0, V0)]}
∨ ∃ η1 l1 V1 eid, s = Linked η1 l1
∧ ζ = <[(t0 + 1)%positive:=(#l1, V1)]> {[ t0 := (#0, V0)]}
∧ T !! η1 = Some eid ⌝.
Proof.
rewrite LinkRes_unfold.
iIntros "[%|H]"; [by iLeft|iRight].
iDestruct "H" as (η1 l1 V1 eid ? (?&?&?)) "_". iPureIntro. subst.
by exists η1, l1, V1, eid.
Qed.
Lemma LinkRes_emap_mono E E' T η l d s t0 V0 ζ :
E ⊑ E' → LinkRes E T η l d s t0 V0 ζ ⊢ LinkRes E' T η l d s t0 V0 ζ.
Proof.
iIntros (SubE'). rewrite /LinkRes. destruct s as [[]|]; [|done].
iDestruct 1 as (V eid v1) "(F & F' & SE & LV & ?)".
iExists V, eid, v1. iFrame. by rewrite seen_enqueued_val_map_mono.
Qed.
Lemma LinkRes_tmap_mono E T T' η l d s t0 V0 ζ :
T ⊆ T' → LinkRes E T η l d s t0 V0 ζ ⊢ LinkRes E T' η l d s t0 V0 ζ.
Proof.
iIntros (SubE'). rewrite /LinkRes. destruct s as [[]|]; [|done].
iDestruct 1 as (V eid v1) "(F & % & ? & ? & ?)".
iExists V, eid, v1. iFrame. iPureIntro. by eapply lookup_weaken.
Qed.
Lemma LinkRes_mono E E' T T' η l d s t0 V0 ζ :
E ⊑ E' → T ⊆ T' → LinkRes E T η l d s t0 V0 ζ ⊢ LinkRes E' T' η l d s t0 V0 ζ.
Proof.
intros S1 S2. rewrite LinkRes_emap_mono; last exact S1.
rewrite LinkRes_tmap_mono; last exact S2. done.
Qed.
Lemma Link_map_mono E E' T T' η l d s :
E ⊑ E' → T ⊆ T' → Link E T η l d s ⊢ Link E' T' η l d s.
Proof.
iIntros (S1 S2). iDestruct 1 as (t0 V0 ζ) "[AT LR]".
iExists t0, V0, ζ. iFrame "AT". by rewrite LinkRes_mono.
Qed.
Lemma LinkRes_dup E T η l d s t0 V0 ζ :
LinkRes E T η l d s t0 V0 ζ ⊢ LinkRes E T η l true s t0 V0 ζ.
Proof.
rewrite /LinkRes. destruct s; [|done]. destruct n.
iDestruct 1 as (V eid v1) "(F & F' & ? & ? & ?)".
iExists V, eid, v1. by iFrame.
Qed.
(* Needed for CAS:
any value in a history of the Link field is comparable to 0. *)
Lemma LinkRes_comparable_0 E T η l d s t0 V0 ζ :
LinkRes E T η l d s t0 V0 ζ ⊢
⌜∀ t v, fst <$> ζ !! t = Some v → ∃ vl : lit, v = #vl ∧ lit_comparable 0 vl⌝.
Proof.
rewrite LinkRes_case_pure. iPureIntro.
intros CASE t v [[v1 V1] [<- Eq]]%lookup_fmap_Some'. simpl.
destruct CASE as [[-> ->]|(η1 & l1 & V1' & eid & -> & -> & _)].
- apply lookup_singleton_Some in Eq as []. simplify_eq.
exists 0. split; [done|constructor].
- case (decide (t = (t0 + 1)%positive)) => ?.
+ subst. rewrite lookup_insert in Eq. simplify_eq.
exists l1. split; [done|constructor].
+ rewrite lookup_insert_ne // in Eq.
apply lookup_singleton_Some in Eq as []. simplify_eq.
exists 0. split; [done|constructor].
Qed.
(* Nodes resources *)
Lemma own_nodes_map_mono E E' T T' η s D L :
E ⊑ E' → T ⊆ T' → own_nodes E T η s D L ⊢ own_nodes E' T' η s D L.
Proof. intros. apply big_sepL2_mono => i [??] [??] ??. by apply Link_map_mono. Qed.
Lemma own_nodes_access E T η0 s0 D L η n :
let CL := (η0, s0) :: D ++ L in
let lenD := length D in
let lenL := S (length L) in
let infos := zip (next_nodes CL) (dequeue_mask lenD lenL) in
(η,n) ∈ CL →
own_nodes E T η0 s0 D L ⊢
∃ d ηs i,
⌜ CL !! i = Some (η, n) ∧ infos !! i = Some (ηs, d) ⌝ ∗
Link E T η n d ηs ∗
( (* return as is *)
(Link E T η n d ηs -∗ own_nodes E T η0 s0 D L) ∧
(* append *)
(∀ E' T' η' n', ⌜ ηs = None ∧ i = (length CL - 1)%nat ∧ E ⊑ E' ∧ T ⊆ T'⌝ →
Link E' T' η n d (Some (η', n')) -∗
Link E' T' η' n' false None -∗
own_nodes E' T' η0 s0 D (L ++ [(η', n')]))
).
Proof.
iIntros (CL lenD lenL infos Inη) "Ns". rewrite /own_nodes.
iDestruct (big_sepL2_length with "Ns") as %EqL.
destruct (elem_of_list_lookup_1 _ _ Inη) as [i Eqη].
destruct (lookup_lt_is_Some_2 infos i) as [[ηs d] Eq].
{ rewrite -EqL. by apply (lookup_lt_Some _ _ _ Eqη). }
iExists d, ηs, i. iSplit; [done|].
iDestruct (big_sepL2_delete' _ _ _ _ _ _ Eqη Eq with "Ns") as "[Linkη Ns]".
iFrame "Linkη".
iSplit.
- iIntros "Linkη". iCombine "Linkη" "Ns" as "Ns".
by rewrite -(big_sepL2_delete' _ _ _ _ _ _ Eqη Eq).
- iIntros (E' T' η' n' (? & Eqi & SubE & SubT)) "Lη Lη'". subst ηs.
assert (∃ L, CL = L ++ [((η, n))]) as [L' EqCL].
{ apply lookup_last_Some. by rewrite -Eqi. }
rewrite /infos EqCL.
rewrite (_: (η0, s0) :: D ++ L ++ [(η', n')] = (L' ++ [(η, n)]) ++ [(η', n')]);
last first.
{ clear -EqCL. rewrite -EqCL. by simplify_list_eq. }
destruct (next_nodes_app_2 L' (η, n) (η', n')) as (LS' & Eq1' & Eq2' & EqLLS').
rewrite Eq1' Eq2'.
assert (EqLCL: length CL = (lenD + lenL)%nat).
{ by rewrite /CL (app_length (_::_)) /= /lenD /lenL Nat.add_succ_r. }
assert (Eqi' : i = (lenD + lenL - 1)%nat).
{ by rewrite Eqi EqLCL. }
assert (∃ Ld, (dequeue_mask lenD lenL) = Ld ++ [d]) as [Ld EqLd].
{ apply lookup_last_Some. rewrite dequeue_mask_length -Eqi'.
clear -Eq. apply lookup_zip_with_Some in Eq as (?&?&?&_&?).
by simplify_eq. }
rewrite app_length Nat.add_1_r dequeue_mask_append EqLd.
have EqLSd: length LS' = length Ld.
{ have EqL1 : S (length Ld) = (lenD + lenL)%nat.
{ by rewrite -dequeue_mask_length EqLd app_length /= Nat.add_1_r. }
have EqL2 : S (length LS') = length CL.
{ by rewrite EqCL app_length /= Nat.add_1_r EqLLS'. }
clear -EqL1 EqL2 EqLCL. move : EqL2. rewrite EqLCL -EqL1. lia. }
rewrite zip_with_app // /= zip_with_app; last first.
{ clear -EqLSd. rewrite 2!app_length /=. lia. }
rewrite zip_with_app // /=.
rewrite big_sepL2_app_same_length; last by right.
rewrite big_sepL2_app_same_length; last by right.
rewrite big_sepL2_app_same_length; last by right.
iDestruct "Ns" as "[Ns _]". iSplitR "Lη'"; first iSplitL "Ns".
+ iApply (big_sepL2_mono with "Ns").
iIntros (j [η1 n1] [η2 n2] Eq1 Eq2) "Link".
iSpecialize ("Link" with "[%]").
{ clear -EqCL Eqi Eq1. intros ?. subst j.
move : Eqi. rewrite EqCL app_length /= Nat.add_sub => ?. subst i.
apply lookup_lt_Some in Eq1. lia. }
by iApply (Link_map_mono with "Link").
+ simpl. by iFrame "Lη".
+ simpl. by iFrame "Lη'".
Qed.
Lemma Link_dequeue E T η' n' η n :
Link E T η' n' false (Some (η, n)) ⊢
Link E T η' n' true (Some (η, n)) ∗
∃ eid eV v, ⌜ T !! η = Some eid ∧ E !! eid = Some eV ∧ ge_event eV = Enq v ⌝ ∗