diff --git a/src/main/frontend/handler/events.cljs b/src/main/frontend/handler/events.cljs index 2a84221da..eaf527325 100644 --- a/src/main/frontend/handler/events.cljs +++ b/src/main/frontend/handler/events.cljs @@ -188,12 +188,13 @@ (defmethod handle :graph/switch [[_ graph opts]] (let [^js sqlite @db-browser/*worker] - (p/let [writes-finished? (when sqlite (.file-writes-finished? sqlite))] - (if (or writes-finished? (:sync-graph/init? @state/state)) - (graph-switch-on-persisted graph opts) + (p/let [writes-finished? (when sqlite (.file-writes-finished? sqlite)) + request-finished? (ldb/request-finished?)] + (if (or (not request-finished?) (not writes-finished?)) ; TODO: test (:sync-graph/init? @state/state) (notification/show! "Please wait seconds until all changes are saved for the current graph." - :warning))))) + :warning) + (graph-switch-on-persisted graph opts))))) (defmethod handle :graph/pull-down-remote-graph [[_ graph dir-name]] (if (mobile-util/native-ios?) diff --git a/src/main/frontend/worker/file.cljs b/src/main/frontend/worker/file.cljs index a12910b8f..6b873e7c6 100644 --- a/src/main/frontend/worker/file.cljs +++ b/src/main/frontend/worker/file.cljs @@ -2,6 +2,7 @@ "Save pages to files for file-based graphs" (:require [clojure.core.async :as async] [clojure.string :as string] + [clojure.set :as set] [frontend.worker.file.core :as file] [logseq.outliner.tree :as otree] [lambdaisland.glogi :as log] @@ -13,17 +14,20 @@ [malli.core :as m] [frontend.worker.state :as state] [goog.object :as gobj] - [logseq.db.sqlite.util :as sqlite-util])) + [logseq.db.sqlite.util :as sqlite-util] + [logseq.common.util :as common-util])) (def *writes file/*writes) (def dissoc-request! file/dissoc-request!) +(def conj-page-write! file/conj-page-write!) (defonce file-writes-chan (let [coercer (m/coercer [:catn [:repo :string] [:page-id :any] [:outliner-op :any] - [:epoch :int]])] + [:epoch :int] + [:request-id :int]])] (async/chan 10000 (map coercer)))) (def batch-write-interval 1000) @@ -55,7 +59,7 @@ (dissoc block :db/id :block/page))) (defn do-write-file! - [repo conn page-db-id outliner-op context] + [repo conn page-db-id outliner-op context request-id] (let [page-block (d/pull @conn '[*] page-db-id) page-db-id (:db/id page-block) whiteboard? (contains? (set (:block/type page-block)) "whiteboard") @@ -65,7 +69,7 @@ (when (or (>= blocks-count 1) blocks-just-deleted?) (if (and (or (> blocks-count 500) whiteboard?) (not (state/tx-idle? repo {:diff 3000}))) - (async/put! file-writes-chan [repo page-db-id outliner-op (tc/to-long (t/now))]) + (async/put! file-writes-chan [repo page-db-id outliner-op (tc/to-long (t/now)) request-id]) (let [pull-keys (if whiteboard? whiteboard-blocks-pull-keys-with-persisted-ids '[*]) blocks (ldb/get-page-blocks @conn (:block/name page-block) {:pull-keys pull-keys}) blocks (if whiteboard? (map cleanup-whiteboard-block blocks) blocks)] @@ -76,22 +80,28 @@ (let [tree-or-blocks (if whiteboard? blocks (otree/blocks->vec-tree repo @conn blocks (:block/name page-block)))] (if page-block - (file/save-tree! repo conn page-block tree-or-blocks blocks-just-deleted? context) + (file/save-tree! repo conn page-block tree-or-blocks blocks-just-deleted? context request-id) (js/console.error (str "can't find page id: " page-db-id)))))))))) (defn write-files! [conn pages context] (when (seq pages) - (doseq [[repo page-id outliner-op] (set (map #(take 3 %) pages))] ; remove time to dedupe pages to write - (try (do-write-file! repo conn page-id outliner-op context) - (catch :default e - (worker-util/post-message :notification - (pr-str - [[:div - [:p "Write file failed, please copy the changes to other editors in case of losing data."] - "Error: " (str (gobj/get e "stack"))] - :error])) - (log/error :file/write-file-error {:error e})))))) + (let [all-request-ids (set (map last pages)) + distincted-pages (common-util/distinct-by #(take 3 %) pages) + repeated-ids (set/difference all-request-ids (set (map last distincted-pages)))] + (doseq [id repeated-ids] + (dissoc-request! id)) + + (doseq [[repo page-id outliner-op _time request-id] distincted-pages] + (try (do-write-file! repo conn page-id outliner-op context request-id) + (catch :default e + (worker-util/post-message :notification + (pr-str + [[:div + [:p "Write file failed, please copy the changes to other editors in case of losing data."] + "Error: " (str (gobj/get e "stack"))] + :error])) + (log/error :file/write-file-error {:error e}))))))) (defn sync-to-file [repo page-id tx-meta] @@ -99,7 +109,8 @@ page-id (not (:created-from-journal-template? tx-meta)) (not (:delete-files? tx-meta))) - (async/put! file-writes-chan [repo page-id (:outliner-op tx-meta) (tc/to-long (t/now))]))) + (let [request-id (conj-page-write! page-id)] + (async/put! file-writes-chan [repo page-id (:outliner-op tx-meta) (tc/to-long (t/now)) request-id])))) (defn page-block :block/file :db/id) file-path (-> (d/entity db file-db-id) :file/path)] @@ -165,8 +165,7 @@ (when-not (and (string/blank? new-content) (not blocks-just-deleted?)) (let [files [[file-path new-content]]] (when (seq files) - (let [page-id (:db/id page-block) - request-id (conj-page-write! page-id)] + (let [page-id (:db/id page-block)] (util/post-message :write-files (pr-str {:request-id request-id :page-id page-id :repo repo @@ -175,10 +174,10 @@ (js/console.error "File path from page-block is not valid" page-block tree)))) (defn save-tree! - [repo conn page-block tree blocks-just-deleted? context] + [repo conn page-block tree blocks-just-deleted? context request-id] {:pre [(map? page-block)]} (when repo - (let [ok-handler #(save-tree-aux! repo @conn page-block tree blocks-just-deleted? context) + (let [ok-handler #(save-tree-aux! repo @conn page-block tree blocks-just-deleted? context request-id) file (or (:block/file page-block) (when-let [page-id (:db/id (:block/page page-block))] (:block/file (d/entity @conn page-id))))] diff --git a/src/main/frontend/worker/pipeline.cljs b/src/main/frontend/worker/pipeline.cljs index c27dbf171..499469b67 100644 --- a/src/main/frontend/worker/pipeline.cljs +++ b/src/main/frontend/worker/pipeline.cljs @@ -75,8 +75,10 @@ (if (or from-disk? new-graph?) {:tx-report tx-report} (let [{:keys [pages blocks]} (ds-report/get-blocks-and-pages tx-report) - _ (doseq [page pages] - (file/sync-to-file repo (:db/id page) tx-meta)) + _ (when (sqlite-util/local-file-based-graph? repo) + (let [page-ids (distinct (map :db/id pages))] + (doseq [page-id page-ids] + (file/sync-to-file repo page-id tx-meta)))) deleted-block-uuids (set (outliner-pipeline/filter-deleted-blocks (:tx-data tx-report))) replace-tx (concat ;; block path refs