瀏覽代碼

fix: use worker weblock to detect whether it's still alive

Use sqlite transaction .changes to determine whether it's writable.
Tienson Qin 2 月之前
父節點
當前提交
9f21cb133f

+ 7 - 13
src/main/frontend/handler/editor.cljs

@@ -353,19 +353,13 @@
                                     :block/name (util/page-name-sanity-lc (:block/title new-block)))
                              (dissoc :block/page)))
                      new-block)]
-    (->
-     (ui-outliner-tx/transact!
-      {:outliner-op :insert-blocks}
-      (save-current-block! {:current-block current-block})
-      (outliner-op/insert-blocks! [new-block'] current-block {:sibling? sibling?
-                                                              :keep-uuid? keep-uuid?
-                                                              :ordered-list? ordered-list?
-                                                              :replace-empty-target? replace-empty-target?}))
-     (p/timeout 2000)
-     (p/catch (fn [error]
-                (js/console.error error)
-                (state/pub-event! [:capture-error {:error error
-                                                   :payload {:type :insert-block-timeout}}]))))))
+    (ui-outliner-tx/transact!
+     {:outliner-op :insert-blocks}
+     (save-current-block! {:current-block current-block})
+     (outliner-op/insert-blocks! [new-block'] current-block {:sibling? sibling?
+                                                             :keep-uuid? keep-uuid?
+                                                             :ordered-list? ordered-list?
+                                                             :replace-empty-target? replace-empty-target?}))))
 
 (defn- block-self-alone-when-insert?
   [config uuid]

+ 1 - 0
src/main/frontend/handler/events.cljs

@@ -157,6 +157,7 @@
 (defmethod handle :graph/sync-context []
   (let [context {:dev? config/dev?
                  :node-test? util/node-test?
+                 :mobile? (util/mobile?)
                  :validate-db-options (:dev/validate-db-options (state/get-config))
                  :importing? (:graph/importing @state/state)
                  :date-formatter (state/get-date-formatter)

+ 8 - 0
src/main/frontend/handler/worker.cljs

@@ -6,6 +6,7 @@
             [frontend.handler.notification :as notification]
             [frontend.state :as state]
             [frontend.undo-redo :as undo-redo]
+            [frontend.util :as util]
             [lambdaisland.glogi :as log]
             [logseq.db :as ldb]
             [promesa.core :as p]))
@@ -54,6 +55,13 @@
 (defmethod handle :export-current-db [_]
   (state/pub-event! [:db/export-sqlite]))
 
+(defmethod handle :reload-app [_]
+  (log/error ::db-read-only nil)
+  ;; (if (util/mobile?)
+  ;;   (js/window.location.reload)
+  ;;   (log/error ::db-read-only nil))
+  )
+
 (defmethod handle :record-worker-client-id [_ _worker data]
   (when-let [client-id (:client-id data)]
     (reset! state/*db-worker-client-id client-id)))

+ 1 - 0
src/main/frontend/persist_db/browser.cljs

@@ -72,6 +72,7 @@
   (let [;; TODO: a better way to share those information with worker, maybe using the state watcher to notify the worker?
         context {:dev? config/dev?
                  :node-test? util/node-test?
+                 :mobile? (util/mobile?)
                  :validate-db-options (:dev/validate-db-options (state/get-config))
                  :importing? (:graph/importing @state/state)
                  :date-formatter (state/get-date-formatter)

+ 26 - 13
src/main/frontend/worker/db_worker.cljs

@@ -139,14 +139,26 @@
       (rebuild-db-from-datoms! conn sqlite-db)
       (worker-util/post-message :notification ["The graph has been successfully rebuilt." :success false]))))
 
+(defn- check-db-writable
+  [^js db]
+  (let [changes (.changes db)]
+    (when (worker-state/mobile?)
+      (log/info ::db-changes-count {:changes changes})
+      (when (< (.changes db) 1)
+        (log/error ::sqlite-upsert-addr-content-failed nil)
+        (reset! worker-state/*db-read-only? true)
+        (worker-util/post-message :reload-app nil)))))
+
 (defn upsert-addr-content!
   "Upsert addr+data-seq. Update sqlite-cli/upsert-addr-content! when making changes"
   [db data]
   (assert (some? db) "sqlite db not exists")
-  (.transaction db (fn [tx]
-                     (doseq [item data]
-                       (.exec tx #js {:sql "INSERT INTO kvs (addr, content, addresses) values ($addr, $content, $addresses) on conflict(addr) do update set content = $content, addresses = $addresses"
-                                      :bind item})))))
+  (.transaction
+   db
+   (fn [tx]
+     (doseq [item data]
+       (.exec tx #js {:sql "INSERT INTO kvs (addr, content, addresses) values ($addr, $content, $addresses) on conflict(addr) do update set content = $content, addresses = $addresses"
+                      :bind item})))))
 
 (defn restore-data-from-addr
   "Update sqlite-cli/restore-data-from-addr when making changes"
@@ -179,7 +191,8 @@
                            :$content (sqlite-util/transit-write data')
                            :$addresses addresses}))
                   addr+data-seq)]
-        (upsert-addr-content! db data)))
+        (upsert-addr-content! db data)
+        (check-db-writable db)))
 
     (-restore [_ addr]
       (restore-data-from-addr db addr))))
@@ -410,7 +423,8 @@
 (def-thread-api :thread-api/create-or-open-db
   [repo opts]
   (when-not (= repo (worker-state/get-current-repo)) ; graph switched
-    (reset! worker-state/*deleted-block-uuid->db-id {}))
+    (reset! worker-state/*deleted-block-uuid->db-id {})
+    (reset! worker-state/*db-read-only? false))
   (start-db! repo opts))
 
 (def-thread-api :thread-api/q
@@ -617,9 +631,15 @@
   [repo ops opts]
   (when-let [conn (worker-state/get-datascript-conn repo)]
     (try
+      (when (worker-state/mobile?)
+        (log/info ::apply-outliner-ops ops)
+        (log/info ::before-apply-outliner-ops ops
+                  ::tx-id (:max-tx @conn)))
       (worker-util/profile
        "apply outliner ops"
        (outliner-op/apply-ops! repo conn ops (worker-state/get-date-formatter repo) opts))
+      (when (worker-state/mobile?)
+        (log/info ::after-tx-id (:max-tx @conn)))
       (catch :default e
         (let [data (ex-data e)
               {:keys [type payload]} (when (map? data) data)]
@@ -768,13 +788,6 @@
   [repo]
   (js/Promise. (embedding/task--update-index-info! repo)))
 
-(def-thread-api :thread-api/check-worker-status
-  [repo]
-  (when repo
-    (let [conn (worker-state/get-datascript-conn repo)]
-      (when @conn
-        {:available? (some? (d/entity @conn :logseq.class/Tag))}))))
-
 (def-thread-api :thread-api/mobile-logs
   []
   @worker-state/*log)

+ 5 - 0
src/main/frontend/worker/state.cljs

@@ -6,6 +6,7 @@
 (defonce *main-thread (atom nil))
 (defonce *infer-worker (atom nil))
 (defonce *deleted-block-uuid->db-id (atom {}))
+(defonce *db-read-only? (atom false))
 
 (defn- <invoke-main-thread*
   [qkw direct-pass? args-list]
@@ -130,6 +131,10 @@
   []
   (:auth/id-token @*state))
 
+(defn mobile?
+  []
+  (:mobile? (get-context)))
+
 ;;; ========================== mobile log ======================================
 (defonce *log (atom []))
 (defn log-append!

+ 8 - 11
src/main/mobile/init.cljs

@@ -73,17 +73,14 @@
       (if (not is-active?)
         (editor-handler/save-current-block!)
         ;; check whether db-worker is available
-        (when @state/*db-worker-client-id
-          (->
-           (p/timeout
-            (p/let [{:keys [available?]} (state/<invoke-db-worker :thread-api/check-worker-status (state/get-current-repo))]
-              (log/info ::check-worker-state {:available? available?})
-              (when-not available?
-                (js/window.location.reload)))
-            500)
-           (p/catch (fn [error]
-                      (js/console.error error)
-                      (js/window.location.reload))))))))
+        (when-let [client-id @state/*db-worker-client-id]
+          (when @state/*db-worker
+            (js/navigator.locks.request client-id #js {:mode "exclusive"
+                                                       :ifAvailable true}
+                                        (fn [lock]
+                                          (when lock
+                                            ;; lock acquired, meaning the worker has terminated
+                                            (js/window.location.reload)))))))))
   (reset! mobile-flows/*mobile-app-state (.-isActive state)))
 
 (defn- general-init