From 2eef88a269572754a1379120acb72a16e633f75c Mon Sep 17 00:00:00 2001 From: Brent Vukmer Date: Thu, 29 Apr 2021 12:22:42 -0400 Subject: [PATCH] Resolves #4; guards synchronize operation inside schema.core/converge against the case where c1 is from a remote node. --- src/schism/core.cljc | 13 ++++++++++++- test/schism/core_test.cljc | 16 +++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/schism/core.cljc b/src/schism/core.cljc index af43c3d..dff5f3b 100644 --- a/src/schism/core.cljc +++ b/src/schism/core.cljc @@ -57,6 +57,15 @@ [& args] (apply nvector/new-vector args)) +(defn- is-local-node? + [n] + "Checks the most recent update in this entity's vector clock. Returns true if that most recent update is not from most-recent schism.node/*current-node*" + (let [most-recent (->> (into [] (sp/get-clock n)) + (sort-by second) + last + first)] + (= most-recent schism.node/*current-node*))) + (defn converge "Return a converged copy of `c1` containing the modifications of `c2`. Convergence is defined on a per-type basis. If `c1` has @@ -71,7 +80,9 @@ - The current value of `schism.node/*current-node*` is shared with another node making modifications to the same logical collection." [c1 c2] - (sp/synchronize c1 c2)) + (if (is-local-node? c1) + (sp/synchronize c1 c2) + (throw (IllegalArgumentException. "The most recent update in c1's vector clock is not from the local node. schism.core/converge expects the c1 param to be the local node and the c2 param to be the remote node. Please check whether you have reversed that order.")))) (def initialize-node! "Initialize the current node to an edn serializable value if diff --git a/test/schism/core_test.cljc b/test/schism/core_test.cljc index 50c9852..69b400c 100644 --- a/test/schism/core_test.cljc +++ b/test/schism/core_test.cljc @@ -29,7 +29,21 @@ #?(:cljs (gen/such-that #(not (js/Number.isNaN %)) gen/any) :clj gen/any)) - +(deftest handles-non-local-copy-as-first-param + (let [m1 (schism/with-node "LOCAL" (schism/convergent-map :foo "bar", :a "b")) + _ (Thread/sleep 1) + m2 (schism/with-node "NOT LOCAL" (schism/convergent-map :y 2, :z 3, :x 1))] + (testing "FIXME, I fail." + (is + (thrown-with-msg? IllegalArgumentException + #"The most recent update in c1's vector clock is not from the local node. schism.core/converge expects the c1 param to be the local node and the c2 param to be the remote node. Please check whether you have reversed that order." + (schism/with-node "LOCAL" (schism/converge m2 m1)))) + ;; We haven't broken existing code in the case where the order is correct (c1 is the local node) + (is (= {:y 2, :z 3, :x 1} + (->> + (schism/with-node "LOCAL" (schism/converge m1 m2)) + seq + (into {}))))))) (defspec convergent-set-is-equivalent-to-hash-set 50