[英]datalevin, concurrency, transactions
我正在使用最新的Datalevin版本0.7.8
並編寫了以下小程序:
(ns datalevintest.core
(:require [datalevin.core :as dc]))
(def store (System/getenv "DBSTORE"))
(def conn (datalevin.core/get-conn store {} {:auto-entity-time? true :validate-data? true}))
(defn -main [& _]
(dotimes [i 5]
(future
(locking ::println (println "Starting thread"))
(try
(dotimes [j 100]
(dc/transact! conn [{:i+j (+ i j)}])
(dc/with-transaction [tx-conn conn]
(dc/transact! tx-conn [{:i*j (* i j)}]))
(dc/q '[:find (pull ?e [*]) :in $ ?id :where [?e :db/id ?id]]
(dc/db conn) 2345))
(catch Throwable t (.printStackTrace t))
(finally (println "Thread" i "done")))))
(println "END"))
不確定地,有時我會得到以下信息:
clojure.lang.ExceptionInfo: Fail to transact to LMDB: "Transaction is not in ready state" {}
at datalevin.binding.java.LMDB.transact_kv(java.clj:484)
at datalevin.storage.Store.load_datoms(storage.cljc:376)
at datalevin.db$local_transact_tx_data.invokeStatic(db.cljc:1236)
at datalevin.db$local_transact_tx_data.invoke(db.cljc:963)
at datalevin.db$transact_tx_data.invokeStatic(db.cljc:1274)
at datalevin.db$transact_tx_data.invoke(db.cljc:1250)
at datalevin.core$with.invokeStatic(core.cljc:291)
at datalevin.core$with.invoke(core.cljc:285)
at datalevin.core$with.invokeStatic(core.cljc:288)
at datalevin.core$with.invoke(core.cljc:285)
at datalevin.core$_transact_BANG_$fn__13128$fn__13129.invoke(core.cljc:550)
at clojure.lang.Atom.swap(Atom.java:37)
at clojure.core$swap_BANG_.invokeStatic(core.clj:2356)
at clojure.core$swap_BANG_.invoke(core.clj:2349)
at datalevin.core$_transact_BANG_$fn__13128.invoke(core.cljc:549)
at datalevin.core$_transact_BANG_.invokeStatic(core.cljc:548)
at datalevin.core$_transact_BANG_.invoke(core.cljc:545)
at datalevin.core$transact_BANG_.invokeStatic(core.cljc:643)
at datalevin.core$transact_BANG_.invoke(core.cljc:555)
at datalevin.core$transact_BANG_.invokeStatic(core.cljc:640)
at datalevin.core$transact_BANG_.invoke(core.cljc:555)
at datalevintest.core$save_BANG_.invokeStatic(core.clj:10)
at datalevintest.core$save_BANG_.doInvoke(core.clj:9)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at datalevintest.core$_main$fn__13261$fn__13265.invoke(core.clj:32)
at datalevintest.core$_main$fn__13261.invoke(core.clj:27)
at clojure.core$binding_conveyor_fn$fn__5772.invoke(core.clj:2034)
at clojure.lang.AFn.call(AFn.java:18)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
(您可能需要多次運行該程序才能得到錯誤。)
我很少得到以下信息:
clojure.lang.ExceptionInfo: Fail to get-first: nil {:dbi "datalevin/eav", :k-range [:all-back], :k-type :eav, :v-type :id}
at datalevin.scan$get_first.invokeStatic(scan.cljc:233)
at datalevin.scan$get_first.invoke(scan.cljc:229)
at datalevin.binding.java.LMDB.get_first(java.clj:502)
at datalevin.binding.java.LMDB.get_first(java.clj:500)
at datalevin.storage.Store.init_max_eid(storage.cljc:300)
at datalevin.db$new_db.invokeStatic(db.cljc:387)
at datalevin.db$new_db.invoke(db.cljc:379)
at datalevintest.core$_main$fn__13261$fn__13265$fn__13276.invoke(core.clj:30)
at datalevintest.core$_main$fn__13261$fn__13265.invoke(core.clj:30)
at datalevintest.core$_main$fn__13261.invoke(core.clj:27)
at clojure.core$binding_conveyor_fn$fn__5772.invoke(core.clj:2034)
at clojure.lang.AFn.call(AFn.java:18)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
如果我使用create-conn
將連接的創建移到未來,我會得到另一個異常:
java.lang.NullPointerException: Cannot read field "e"
at datalevin.storage.Store.init_max_eid(storage.cljc:302)
at datalevin.db$new_db.invokeStatic(db.cljc:387)
at datalevin.db$new_db.invoke(db.cljc:379)
at datalevin.db$empty_db.invokeStatic(db.cljc:399)
at datalevin.db$empty_db.invoke(db.cljc:392)
at datalevin.core$create_conn.invokeStatic(core.cljc:529)
at datalevin.core$create_conn.invoke(core.cljc:488)
at datalevintest.core$_main$fn__13252.invoke(core.clj:14)
at clojure.core$binding_conveyor_fn$fn__5772.invoke(core.clj:2034)
at clojure.lang.AFn.call(AFn.java:18)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
(這也破壞了數據庫文件,因此應用程序不會在下次啟動。)
該問題出現在多線程環境中,聽起來像是並發問題。 我的第一個想法是不應該跨不同的線程使用同一個連接,但是, get-conn 的代碼說同一個連接將在目錄已經存在時被重用。 該文檔沒有提到多線程。
我的代碼中導致問題的錯誤是什么,我怎樣才能讓它更安全?
問題發布后半小時發布的0.7.9
版本修復了此錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.