mirror of
https://github.com/logseq/logseq.git
synced 2026-06-01 19:01:22 +00:00
fix(rtc): batch store and validate db (#12249)
* fix(rtc): batch store and validate db * fix: logseq.db/transact! shouldn't distinct tx-data since move-op include 2 steps: 1. insert-block 2. update-attrs This results in db invalid after step 1. * refactor: add transact-with-temp-conn! * bump nbb-logseq and add tests for ldb/transact* fns --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: rcmerci <rcmerci@gmail.com>
This commit is contained in:
@@ -21,7 +21,6 @@
|
||||
[logseq.db.common.property-util :as db-property-util]
|
||||
[logseq.db.frontend.property :as db-property]
|
||||
[logseq.graph-parser.whiteboard :as gp-whiteboard]
|
||||
[logseq.outliner.batch-tx :as batch-tx]
|
||||
[logseq.outliner.core :as outliner-core]
|
||||
[logseq.outliner.transaction :as outliner-tx]
|
||||
[missionary.core :as m]))
|
||||
@@ -192,9 +191,11 @@
|
||||
(when-let [target-b
|
||||
(d/entity @conn (:db/id (:block/page (d/entity @conn [:block/uuid block-uuid]))))]
|
||||
(transact-db! :move-blocks&persist-op repo conn [b] target-b {:sibling? false}))))
|
||||
(doseq [block-uuid block-uuids-to-remove]
|
||||
(when-let [b (d/entity @conn [:block/uuid block-uuid])]
|
||||
(transact-db! :delete-blocks repo conn date-formatter [b] {}))))))
|
||||
(let [deleting-blocks (keep (fn [block-uuid]
|
||||
(d/entity @conn [:block/uuid block-uuid]))
|
||||
block-uuids-to-remove)]
|
||||
(when (seq deleting-blocks)
|
||||
(transact-db! :delete-blocks repo conn date-formatter deleting-blocks {}))))))
|
||||
|
||||
(defn- insert-or-move-block
|
||||
[repo conn block-uuid remote-parents remote-block-order move? op-value]
|
||||
@@ -209,8 +210,7 @@
|
||||
(if move?
|
||||
(transact-db! :move-blocks repo conn [(block-reuse-db-id b)] local-parent {:sibling? false})
|
||||
(transact-db! :insert-blocks repo conn
|
||||
[{:block/uuid block-uuid
|
||||
:block/title ""}]
|
||||
[{:block/uuid block-uuid}]
|
||||
local-parent {:sibling? false :keep-uuid? true}))
|
||||
(transact-db! :update-block-order-directly repo conn block-uuid first-remote-parent remote-block-order))
|
||||
|
||||
@@ -681,20 +681,25 @@
|
||||
update-ops (vals update-ops-map)
|
||||
update-page-ops (vals update-page-ops-map)
|
||||
remove-page-ops (vals remove-page-ops-map)
|
||||
db-before @conn]
|
||||
db-before @conn
|
||||
tx-meta {:rtc-tx? true
|
||||
:persist-op? false
|
||||
:gen-undo-ops? false}]
|
||||
(rtc-log-and-state/update-remote-t graph-uuid remote-t)
|
||||
(js/console.groupCollapsed "rtc/apply-remote-ops-log")
|
||||
(batch-tx/with-batch-tx-mode conn {:rtc-tx? true
|
||||
:persist-op? false
|
||||
:gen-undo-ops? false}
|
||||
(worker-util/profile :ensure-refed-blocks-exist (ensure-refed-blocks-exist repo conn refed-blocks))
|
||||
(worker-util/profile :apply-remote-update-page-ops (apply-remote-update-page-ops repo conn update-page-ops))
|
||||
(worker-util/profile :apply-remote-move-ops (apply-remote-move-ops repo conn sorted-move-ops))
|
||||
(worker-util/profile :apply-remote-update-ops (apply-remote-update-ops repo conn update-ops))
|
||||
(worker-util/profile :apply-remote-remove-page-ops (apply-remote-remove-page-ops repo conn remove-page-ops)))
|
||||
(ldb/transact-with-temp-conn!
|
||||
conn tx-meta
|
||||
(fn [temp-conn]
|
||||
(worker-util/profile :ensure-refed-blocks-exist (ensure-refed-blocks-exist repo temp-conn refed-blocks))
|
||||
(worker-util/profile :apply-remote-update-page-ops (apply-remote-update-page-ops repo temp-conn update-page-ops))
|
||||
(worker-util/profile :apply-remote-move-ops (apply-remote-move-ops repo temp-conn sorted-move-ops))
|
||||
(worker-util/profile :apply-remote-update-ops (apply-remote-update-ops repo temp-conn update-ops))
|
||||
(worker-util/profile :apply-remote-remove-page-ops (apply-remote-remove-page-ops repo temp-conn remove-page-ops))))
|
||||
|
||||
;; NOTE: we cannot set :persist-op? = true when batch-tx/with-batch-tx-mode (already set to false)
|
||||
;; and there're some transactions in `apply-remote-remove-ops` need to :persist-op?=true
|
||||
(worker-util/profile :apply-remote-remove-ops (apply-remote-remove-ops repo conn date-formatter remove-ops))
|
||||
|
||||
;; wait all remote-ops transacted into db,
|
||||
;; then start to check any asset-updates in remote
|
||||
(let [db-after @conn]
|
||||
|
||||
@@ -156,6 +156,14 @@
|
||||
:logseq.property/status [status-value-uuid2]}}
|
||||
r)))))
|
||||
|
||||
(defn- apply-move-ops!
|
||||
[repo conn move-ops]
|
||||
(ldb/transact-with-temp-conn!
|
||||
conn
|
||||
{}
|
||||
(fn [temp-conn]
|
||||
(#'r.remote/apply-remote-move-ops repo temp-conn move-ops))))
|
||||
|
||||
(deftest apply-remote-move-ops-test
|
||||
(let [repo (state/get-current-repo)
|
||||
conn (conn/get-db repo false)
|
||||
@@ -182,6 +190,7 @@
|
||||
:block/parent [:block/uuid page-uuid]}]
|
||||
(ldb/get-page @conn page-name)
|
||||
{:sibling? false :keep-uuid? true}))
|
||||
|
||||
(testing "apply-remote-move-ops-test1"
|
||||
(let [data-from-ws {:req-id "req-id"
|
||||
:t 1 ;; not used
|
||||
@@ -199,7 +208,7 @@
|
||||
(#'r.remote/affected-blocks->diff-type-ops
|
||||
repo (:affected-blocks data-from-ws))))]
|
||||
(is (rtc-schema/data-from-ws-validator data-from-ws) data-from-ws)
|
||||
(#'r.remote/apply-remote-move-ops repo conn move-ops)
|
||||
(apply-move-ops! repo conn move-ops)
|
||||
(let [page-blocks (ldb/get-page-blocks @conn (:db/id (ldb/get-page @conn page-name)) {})]
|
||||
(is (= #{uuid1-remote uuid1-client uuid2-client} (set (map :block/uuid page-blocks)))
|
||||
[uuid1-remote uuid1-client uuid2-client])
|
||||
@@ -229,7 +238,7 @@
|
||||
(#'r.remote/affected-blocks->diff-type-ops
|
||||
repo (:affected-blocks data-from-ws))))]
|
||||
(is (rtc-schema/data-from-ws-validator data-from-ws))
|
||||
(#'r.remote/apply-remote-move-ops repo conn move-ops)
|
||||
(apply-move-ops! repo conn move-ops)
|
||||
(let [page-blocks (ldb/get-page-blocks @conn (:db/id (ldb/get-page @conn page-name)) {})]
|
||||
(is (= #{uuid1-remote uuid2-remote uuid1-client uuid2-client} (set (map :block/uuid page-blocks))))
|
||||
(is (= ["a0" "a1"]
|
||||
|
||||
43
src/test/logseq/db_test.cljs
Normal file
43
src/test/logseq/db_test.cljs
Normal file
@@ -0,0 +1,43 @@
|
||||
(ns logseq.db-test
|
||||
(:require [cljs.test :refer [deftest is testing] :as t]
|
||||
[datascript.core :as d]
|
||||
[frontend.db.conn :as conn]
|
||||
[frontend.test.helper :as test-helper]
|
||||
[logseq.db :as ldb]))
|
||||
|
||||
;; TODO: move tests to deps/db
|
||||
|
||||
(t/use-fixtures :each
|
||||
test-helper/db-based-start-and-destroy-db-map-fixture)
|
||||
|
||||
(deftest test-transact-with-multiple-tx-datoms
|
||||
(testing "last write wins with same tx"
|
||||
(let [conn (d/create-conn)]
|
||||
(d/transact! conn [[:db/add -1 :property :v1]])
|
||||
(let [tx (:max-tx @conn)]
|
||||
(ldb/transact! conn
|
||||
[(d/datom 1 :property :v1 (inc tx) false)
|
||||
(d/datom 1 :property :v1 (inc tx) true)]))
|
||||
(is (= :v1 (:property (d/entity @conn 1))))))
|
||||
(testing "last write wins with different tx"
|
||||
(let [conn (d/create-conn)]
|
||||
(d/transact! conn [[:db/add -1 :property :v1]])
|
||||
(let [tx (:max-tx @conn)]
|
||||
(ldb/transact! conn
|
||||
[(d/datom 1 :property :v1 (inc tx) false)
|
||||
(d/datom 1 :property :v1 (+ tx 2) true)]))
|
||||
(is (= :v1 (:property (d/entity @conn 1)))))))
|
||||
|
||||
(deftest test-transact-with-temp-conn!
|
||||
(testing "DB validation should be running after the whole transaction"
|
||||
(let [conn (conn/get-db false)]
|
||||
(testing "#Task shouldn't be converted to property"
|
||||
(is (thrown? js/Error (ldb/transact! conn [{:db/ident :logseq.class/Task
|
||||
:block/tags :logseq.class/Property}]))))
|
||||
(ldb/transact-with-temp-conn!
|
||||
conn
|
||||
{}
|
||||
(fn [temp-conn]
|
||||
(ldb/transact! temp-conn [{:db/ident :logseq.class/Task
|
||||
:block/tags :logseq.class/Property}])
|
||||
(ldb/transact! temp-conn [[:db/retract :logseq.class/Task :block/tags :logseq.class/Property]]))))))
|
||||
Reference in New Issue
Block a user