(* Victor B. F. Gomes, University of Cambridge MartinKleppmann,UniversityofCambridge DominicP.Mulligan,UniversityofCambridge AlastairR.Beresford,UniversityofCambridge
*)
definition indices :: "('id × ('id, 'v) operation) event list ==> 'id list"where "indices xs ≡ List.map_filter (λx. case x of Deliver (i, Insert e n) ==> Some (fst e) | _ ==> None) xs"
lemma (in rga) idx_in_elem_inserted [intro]: assumes"Deliver (i, Insert e n) ∈ set xs" shows"fst e ∈ set (indices xs)" using assms by(induction xs, auto simp add: indices_def map_filter_def)
lemma (in rga) apply_opers_idx_elems: assumes"es prefix of i" and"apply_operations es = Some xs" shows"element_ids xs = set (indices es)" using assms unfolding element_ids_def proof(induction es arbitrary: xs rule: rev_induct, clarsimp) case (snoc x xs) thus ?case proof (cases x, clarsimp, blast) case (Deliver e) moreoverobtain a b where"e = (a, b)"by force ultimatelyshow ?thesis using snoc assms apply (cases b; clarsimp split: bind_splits simp add: interp_msg_def) apply (metis Un_insert_right append.right_neutral insert_preserve_indices' list.set(1)
option.sel prefix_of_appendD prod.sel(1) set_append) by (metis delete_preserve_indices prefix_of_appendD) qed qed
lemma (in rga) delete_does_not_change_element_ids: assumes"es @ [Deliver (i, Delete n)] prefix of j" and"apply_operations es = Some xs1" and"apply_operations (es @ [Deliver (i, Delete n)]) = Some xs2" shows"element_ids xs1 = element_ids xs2" proof - have"indices es = indices (es @ [Deliver (i, Delete n)])" by simp thenshow ?thesis by (metis (no_types) assms prefix_of_appendD rga.apply_opers_idx_elems rga_axioms) qed
lemma (in rga) someone_inserted_id: assumes"es @ [Deliver (i, Insert (k, v, f) n)] prefix of j" and"apply_operations es = Some xs1" and"apply_operations (es @ [Deliver (i, Insert (k, v, f) n)]) = Some xs2" and"a ∈ element_ids xs2" and"a ≠ k" shows"a ∈ element_ids xs1" using assms apply_opers_idx_elems by auto
lemma (in rga) deliver_insert_exists: assumes"es prefix of j" and"apply_operations es = Some xs" and"a ∈ element_ids xs" shows"∃i v f n. Deliver (i, Insert (a, v, f) n) ∈ set es" using assms unfolding element_ids_def proof(induction es arbitrary: xs rule: rev_induct, clarsimp) case (snoc x xs ys) thus ?case proof (cases x) case (Broadcast e) thus ?thesis using snoc by(clarsimp, metis image_eqI prefix_of_appendD prod.sel(1)) next case (Deliver e) moreoverthenobtain xs' where *: "apply_operations xs = Some xs'" using snoc by fastforce moreoverobtain k v where **: "e = (k, v)"by force ultimatelyshow ?thesis using assms snoc proof (cases v) case (Insert el _) thus ?thesis using snoc Deliver * ** apply (cases el; cases "fst el = a"; clarsimp) apply (blast, metis (no_types, lifting) element_ids_def prefix_of_appendD set_map snoc.prems(2)
snoc.prems(3) someone_inserted_id) done next case (Delete _) thus ?thesis using snoc Deliver ** apply clarsimp apply(drule prefix_of_appendD, clarsimp simp add: bind_eq_Some_conv interp_msg_def) apply(metis delete_preserve_indices image_eqI prod.sel(1)) done qed qed qed
lemma (in rga) insert_in_apply_set: assumes"es @ [Deliver (i, Insert e (Some a))] prefix of j" and"Deliver (i', Insert e' n) ∈ set es" and"apply_operations es = Some s" shows"fst e' ∈ element_ids s" using assms apply_opers_idx_elems idx_in_elem_inserted prefix_of_appendD by blast
lemma (in rga) insert_msg_id: assumes"Broadcast (i, Insert e n) ∈ set (history j)" shows"fst e = i" proof - obtain state where1: "valid_rga_msg state (i, Insert e n)" using assms broadcast_is_valid by blast thus"fst e = i" by(clarsimp simp add: valid_rga_msg_def split: option.split_asm) qed
lemma (in rga) allowed_insert: assumes"Broadcast (i, Insert e n) ∈ set (history j)" shows"n = None ∨ (∃i' e' n'. n = Some (fst e') ∧ Deliver (i', Insert e' n') ⊏j Broadcast (i, Insert e n))" proof - obtainprewhere1: "pre @ [Broadcast (i, Insert e n)] prefix of j" using assms events_before_exist by blast from this obtain state where2: "apply_operations pre = Some state"and3: "valid_rga_msg state (i, Insert e n)" using broadcast_only_valid_msgs by blast show"n = None ∨ (∃i' e' n'. n = Some (fst e') ∧ Deliver (i', Insert e' n') ⊏j Broadcast (i, Insert e n))" proof(cases n) fix a assume4: "n = Some a" hence"a ∈ element_ids state"and5: "fst e = i" using3by(clarsimp simp add: valid_rga_msg_def)+ from this have"∃i' v' f' n'. Deliver (i', Insert (a, v', f') n') ∈ set pre" using deliver_insert_exists 21by blast thus"n = None ∨ (∃i' e' n'. n = Some (fst e') ∧ Deliver (i', Insert e' n') ⊏j Broadcast (i, Insert e n))" using events_in_local_order 145by(metis fst_conv) qed simp qed
lemma (in rga) allowed_delete: assumes"Broadcast (i, Delete x) ∈ set (history j)" shows"∃i' n' v b. Deliver (i', Insert (x, v, b) n') ⊏j Broadcast (i, Delete x)" proof - obtainprewhere1: "pre @ [Broadcast (i, Delete x)] prefix of j" using assms events_before_exist by blast from this obtain state where2: "apply_operations pre = Some state" and"valid_rga_msg state (i, Delete x)" using broadcast_only_valid_msgs by blast hence"x ∈ element_ids state" using apply_opers_idx_elems by(simp add: valid_rga_msg_def) hence"∃i' v' f' n'. Deliver (i', Insert (x, v', f') n') ∈ set pre" using deliver_insert_exists 12by blast thus"∃i' n' v b. Deliver (i', Insert (x, v, b) n') ⊏j Broadcast (i, Delete x)" using events_in_local_order 1by blast qed
lemma (in rga) insert_id_unique: assumes"fst e1 = fst e2" and"Broadcast (i1, Insert e1 n1) ∈ set (history i)" and"Broadcast (i2, Insert e2 n2) ∈ set (history j)" shows"Insert e1 n1 = Insert e2 n2" using assms insert_msg_id msg_id_unique Pair_inject fst_conv by metis
lemma (in rga) allowed_delete_deliver: assumes"Deliver (i, Delete x) ∈ set (history j)" shows"∃i' n' v b. Deliver (i', Insert (x, v, b) n') ⊏j Deliver (i, Delete x)" using assms by (meson allowed_delete bot_least causal_broadcast delivery_has_a_cause insert_subset)
lemma (in rga) allowed_delete_deliver_in_set: assumes"(es@[Deliver (i, Delete m)]) prefix of j" shows"∃i' n v b. Deliver (i', Insert (m, v, b) n) ∈ set es" by(metis (no_types, lifting) Un_insert_right insert_iff list.simps(15) assms
local_order_prefix_closed_last rga.allowed_delete_deliver rga_axioms set_append subsetCE prefix_to_carriers)
lemma (in rga) allowed_insert_deliver: assumes"Deliver (i, Insert e n) ∈ set (history j)" shows"n = None ∨ (∃i' n' n'' v b. n = Some n' ∧ Deliver (i', Insert (n', v, b) n'') ⊏j Deliver (i, Insert e n))" proof - obtain ja where1: "Broadcast (i, Insert e n) ∈ set (history ja)" using assms delivery_has_a_cause by blast show"n = None ∨ (∃i' n' n'' v b. n = Some n' ∧ Deliver (i', Insert (n', v, b) n'') ⊏j Deliver (i, Insert e n))" proof(cases n) fix a assume3: "n = Some a" from this obtain i' e' n' where4: "Some a = Some (fst e')"and 2: "Deliver (i', Insert e' n') ⊏ja Broadcast (i, Insert e (Some a))" using allowed_insert 1by blast hence"Deliver (i', Insert e' n') ∈ set (history ja)"and"Broadcast (i, Insert e (Some a)) ∈ set (history ja)" using local_order_carrier_closed by simp+ from this obtain jaa where"Broadcast (i, Insert e (Some a)) ∈ set (history jaa)" using delivery_has_a_cause by simp have"∃i' n' n'' v b. n = Some n' ∧ Deliver (i', Insert (n', v, b) n'') ⊏j Deliver (i, Insert e n)" using234by(metis assms causal_broadcast prod.collapse) thus"n = None ∨ (∃i' n' n'' v b. n = Some n' ∧ Deliver (i', Insert (n', v, b) n'') ⊏j Deliver (i, Insert e n))" by auto qed simp qed
lemma (in rga) allowed_insert_deliver_in_set: assumes"(es@[Deliver (i, Insert e m)]) prefix of j" shows"m = None ∨ (∃i' m' n v b. m = Some m' ∧ Deliver (i', Insert (m', v, b) n) ∈ set es)" by(metis assms Un_insert_right insert_subset list.simps(15) set_append prefix_to_carriers
allowed_insert_deliver local_order_prefix_closed_last)
lemma (in rga) Insert_no_failure: assumes"es @ [Deliver (i, Insert e n)] prefix of j" and"apply_operations es = Some s" shows"∃ys. insert s e n = Some ys" by(metis (no_types, lifting) element_ids_def allowed_insert_deliver_in_set assms fst_conv
insert_in_apply_set insert_no_failure set_map)
lemma (in rga) delete_no_failure: assumes"es @ [Deliver (i, Delete n)] prefix of j" and"apply_operations es = Some s" shows"∃ys. delete s n = Some ys" proof - obtain i' na v b where1: "Deliver (i', Insert (n, v, b) na) ∈ set es" using assms allowed_delete_deliver_in_set by blast alsohave"fst (n, v, b) ∈ set (indices es)" using assms idx_in_elem_inserted calculation by blast from this assms and1show"∃ys. delete s n = Some ys" apply - apply(rule delete_no_failure) apply(metis apply_opers_idx_elems element_ids_def prefix_of_appendD prod.sel(1) set_map) done qed
lemma (in rga) Insert_equal: assumes"fst e1 = fst e2" and"Broadcast (i1, Insert e1 n1) ∈ set (history i)" and"Broadcast (i2, Insert e2 n2) ∈ set (history j)" shows"Insert e1 n1 = Insert e2 n2" using insert_id_unique assms by simp
lemma (in rga) same_insert: assumes"fst e1 = fst e2" and"xs prefix of i" and"(i1, Insert e1 n1) ∈ set (node_deliver_messages xs)" and"(i2, Insert e2 n2) ∈ set (node_deliver_messages xs)" shows"Insert e1 n1 = Insert e2 n2" proof - have"Deliver (i1, Insert e1 n1) ∈ set (history i)" using assms by(auto simp add: node_deliver_messages_def prefix_msg_in_history) from this obtain j where1: "Broadcast (i1, Insert e1 n1) ∈ set (history j)" using delivery_has_a_cause by blast have"Deliver (i2, Insert e2 n2) ∈ set (history i)" using assms by(auto simp add: node_deliver_messages_def prefix_msg_in_history) from this obtain k where2: "Broadcast (i2, Insert e2 n2) ∈ set (history k)" using delivery_has_a_cause by blast show"Insert e1 n1 = Insert e2 n2" by(rule Insert_equal; force simp add: assms intro: 12) qed
lemma (in rga) insert_commute_assms: assumes"{Deliver (i, Insert e n), Deliver (i', Insert e' n')} ⊆ set (history j)" and"hb.concurrent (i, Insert e n) (i', Insert e' n')" shows"n = None ∨ n ≠ Some (fst e')" using assms apply(clarsimp simp: hb.concurrent_def) apply(cases e') apply clarsimp apply(frule delivery_has_a_cause) apply(frule delivery_has_a_cause, clarsimp) apply(frule allowed_insert) apply clarsimp apply(metis Insert_equal delivery_has_a_cause fst_conv hb.intros(2) insert_subset
local_order_carrier_closed insert_msg_id) done
lemma subset_reorder: assumes"{a, b} ⊆ c" shows"{b, a} ⊆ c" using assms by simp
lemma (in rga) Insert_Insert_concurrent: assumes"{Deliver (i, Insert e k), Deliver (i', Insert e' (Some m))} ⊆ set (history j)" and"hb.concurrent (i, Insert e k) (i', Insert e' (Some m))" shows"fst e ≠ m" by(metis assms subset_reorder hb.concurrent_comm insert_commute_assms option.simps(3))
lemma (in rga) insert_valid_assms: assumes"Deliver (i, Insert e n) ∈ set (history j)" shows"n = None ∨ n ≠ Some (fst e)" using assms by(meson allowed_insert_deliver hb.concurrent_def hb.less_asym insert_subset
local_order_carrier_closed rga.insert_commute_assms rga_axioms)
lemma (in rga) Insert_Delete_concurrent: assumes"{Deliver (i, Insert e n), Deliver (i', Delete n')} ⊆ set (history j)" and"hb.concurrent (i, Insert e n) (i', Delete n')" shows"n' ≠ fst e" by (metis assms Insert_equal allowed_delete delivery_has_a_cause fst_conv hb.concurrent_def
hb.intros(2) insert_subset local_order_carrier_closed rga.insert_msg_id rga_axioms)
lemma (in rga) concurrent_operations_commute: assumes"xs prefix of i" shows"hb.concurrent_ops_commute (node_deliver_messages xs)" proof - have"∧x y. {x, y} ⊆ set (node_deliver_messages xs) ==> hb.concurrent x y ==> interp_msg x ⊳ interp_msg y = interp_msg y ⊳ interp_msg x" proof fix x y ii assume"{x, y} ⊆ set (node_deliver_messages xs)" and C: "hb.concurrent x y" hence X: "x ∈ set (node_deliver_messages xs)"and Y: "y ∈ set (node_deliver_messages xs)" by auto obtain x1 x2 y1 y2 where1: "x = (x1, x2)"and2: "y = (y1, y2)" by fastforce have"(interp_msg (x1, x2) ⊳ interp_msg (y1, y2)) ii = (interp_msg (y1, y2) ⊳ interp_msg (x1, x2)) ii" proof(cases x2; cases y2) fix ix1 ix2 iy1 iy2 assume X2: "x2 = Insert ix1 ix2"and Y2: "y2 = Insert iy1 iy2" show"(interp_msg (x1, x2) ⊳ interp_msg (y1, y2)) ii = (interp_msg (y1, y2) ⊳ interp_msg (x1, x2)) ii" proof(cases "fst ix1 = fst iy1") assume"fst ix1 = fst iy1" hence"Insert ix1 ix2 = Insert iy1 iy2" apply(rule same_insert) using12 X Y X2 Y2 assms apply auto done hence"ix1 = iy1"and"ix2 = iy2" by auto from this and X2 Y2 show"(interp_msg (x1, x2) ⊳ interp_msg (y1, y2)) ii = (interp_msg (y1, y2) ⊳ interp_msg (x1, x2)) ii" by(clarsimp simp add: kleisli_def interp_msg_def) next assume NEQ: "fst ix1 ≠ fst iy1" have"ix2 = None ∨ ix2 ≠ Some (fst iy1)" apply(rule insert_commute_assms) using prefix_msg_in_history[OF assms] X Y X2 Y2 12 apply(clarsimp, blast) using C 12 X2 Y2 apply blast done alsohave"iy2 = None ∨ iy2 ≠ Some (fst ix1)" apply(rule insert_commute_assms) using prefix_msg_in_history[OF assms] X Y X2 Y2 12 apply(clarsimp, blast) using"1""2" C X2 Y2 apply blast done ultimatelyhave"insert ii ix1 ix2 🍋 (λx. insert x iy1 iy2) = insert ii iy1 iy2 🍋 (λx. insert x ix1 ix2)" using NEQ insert_commutes by blast thus"(interp_msg (x1, x2) ⊳ interp_msg (y1, y2)) ii = (interp_msg (y1, y2) ⊳ interp_msg (x1, x2)) ii" by(clarsimp simp add: interp_msg_def X2 Y2 kleisli_def) qed next fix ix1 ix2 yd assume X2: "x2 = Insert ix1 ix2"and Y2: "y2 = Delete yd" have"hb.concurrent (x1, Insert ix1 ix2) (y1, Delete yd)" using C X2 Y2 12by simp alsohave"{Deliver (x1, Insert ix1 ix2), Deliver (y1, Delete yd)} ⊆ set (history i)" using prefix_msg_in_history assms X2 Y2 X Y 12by blast ultimatelyhave"yd ≠ fst ix1" apply - apply(rule Insert_Delete_concurrent; force) done hence"insert ii ix1 ix2 🍋 (λx. delete x yd) = delete ii yd 🍋 (λx. insert x ix1 ix2)" by(rule insert_delete_commute) thus"(interp_msg (x1, x2) ⊳ interp_msg (y1, y2)) ii = (interp_msg (y1, y2) ⊳ interp_msg (x1, x2)) ii" by(clarsimp simp add: interp_msg_def kleisli_def X2 Y2) next fix xd iy1 iy2 assume X2: "x2 = Delete xd"and Y2: "y2 = Insert iy1 iy2" have"hb.concurrent (x1, Delete xd) (y1, Insert iy1 iy2)" using C X2 Y2 12by simp alsohave"{Deliver (x1, Delete xd), Deliver (y1, Insert iy1 iy2)} ⊆ set (history i)" using prefix_msg_in_history assms X2 Y2 X Y 12by blast ultimatelyhave"xd ≠ fst iy1" apply - apply(rule Insert_Delete_concurrent; force) done hence"delete ii xd 🍋 (λx. insert x iy1 iy2) = insert ii iy1 iy2 🍋 (λx. delete x xd)" by(rule insert_delete_commute[symmetric]) thus"(interp_msg (x1, x2) ⊳ interp_msg (y1, y2)) ii = (interp_msg (y1, y2) ⊳ interp_msg (x1, x2)) ii" by(clarsimp simp add: interp_msg_def kleisli_def X2 Y2) next fix xd yd assume X2: "x2 = Delete xd"and Y2: "y2 = Delete yd" have"delete ii xd 🍋 (λx. delete x yd) = delete ii yd 🍋 (λx. delete x xd)" by(rule delete_commutes) thus"(interp_msg (x1, x2) ⊳ interp_msg (y1, y2)) ii = (interp_msg (y1, y2) ⊳ interp_msg (x1, x2)) ii" by(clarsimp simp add: interp_msg_def kleisli_def X2 Y2) qed thus"(interp_msg x ⊳ interp_msg y) ii = (interp_msg y ⊳ interp_msg x) ii" using12by auto qed thus"hb.concurrent_ops_commute (node_deliver_messages xs)" by(auto simp add: hb.concurrent_ops_commute_def) qed
corollary (in rga) concurrent_operations_commute': shows"hb.concurrent_ops_commute (node_deliver_messages (history i))" by (meson concurrent_operations_commute append.right_neutral prefix_of_node_history_def)
lemma (in rga) apply_operations_never_fails: assumes"xs prefix of i" shows"apply_operations xs ≠ None" using assms proof(induction xs rule: rev_induct) show"apply_operations [] ≠ None" by clarsimp next fix x xs assume1: "xs prefix of i ==> apply_operations xs ≠ None" and2: "xs @ [x] prefix of i" hence3: "xs prefix of i" by auto show"apply_operations (xs @ [x]) ≠ None" proof(cases x) fix b assume"x = Broadcast b" thus"apply_operations (xs @ [x]) ≠ None" using13by clarsimp next fix d assume4: "x = Deliver d" thus"apply_operations (xs @ [x]) ≠ None" proof(cases d; clarify) fix a b assume5: "x = Deliver (a, b)" show"∃y. apply_operations (xs @ [Deliver (a, b)]) = Some y" proof(cases b; clarify) fix aa aaa ba x12 assume6: "b = Insert (aa, aaa, ba) x12" show"∃y. apply_operations (xs @ [Deliver (a, Insert (aa, aaa, ba) x12)]) = Some y" apply(clarsimp simp add: 1 interp_msg_def split!: bind_splits) apply(simp add: "1""3") apply(rule rga.Insert_no_failure, rule rga_axioms) using4562apply force+ done next fix x2 assume6: "b = Delete x2" show"∃y. apply_operations (xs @ [Deliver (a, Delete x2)]) = Some y" apply(clarsimp simp add: interp_msg_def split!: bind_splits) apply(simp add: 13) apply(rule delete_no_failure) using4562apply force+ done qed qed qed qed
corollary (in rga) rga_convergence: assumes"set (node_deliver_messages xs) = set (node_deliver_messages ys)" and"xs prefix of i" and"ys prefix of j" shows"apply_operations xs = apply_operations ys" using assms by(auto simp add: apply_operations_def intro: hb.convergence_ext
concurrent_operations_commute node_deliver_messages_distinct hb_consistent_prefix)
subsection‹Strong eventual consistency›
context rga begin
sublocale sec: strong_eventual_consistency weak_hb hb interp_msg "λops.∃xs i. xs prefix of i ∧ node_deliver_messages xs = ops""[]" proof(standard; clarsimp) fix xsa i assume"xsa prefix of i" thus"hb.hb_consistent (node_deliver_messages xsa)" by(auto simp add: hb_consistent_prefix) next fix xsa i assume"xsa prefix of i" thus"distinct (node_deliver_messages xsa)" by(auto simp add: node_deliver_messages_distinct) next fix xsa i assume"xsa prefix of i" thus"hb.concurrent_ops_commute (node_deliver_messages xsa)" by(auto simp add: concurrent_operations_commute) next fix xs a b state xsa x assume"hb.apply_operations xs [] = Some state" and"node_deliver_messages xsa = xs @ [(a, b)]" and"xsa prefix of x" thus"∃y. interp_msg (a, b) state = Some y" by(metis (no_types, lifting) apply_operations_def bind.bind_lunit not_None_eq
hb.apply_operations_Snoc kleisli_def apply_operations_never_fails interp_msg_def) next fix xs a b xsa x assume"node_deliver_messages xsa = xs @ [(a, b)]" and"xsa prefix of x" thus"∃xsa. (∃x. xsa prefix of x) ∧ node_deliver_messages xsa = xs" using drop_last_message by blast qed
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.