簡體   English   中英

datalevin,並發,交易

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM