首页 > 解决方案 > xodus 游标的有效期是多久?

问题描述

我正在使用 Clojure 的 xodus,并且正在评估以惰性方式遍历所有键/值对的可能性,就像在 Clojure 中很常见一样。

我最初的理解是,所有通过 a 进行的数据访问Cursor都应该发生在 readonly 内部Transaction,因为每个事务都在其自己的数据库快照上运行。

但是,如果您在事务中创建了游标,看起来在事务结束后仍然可以继续迭代同一个事务快照。事实上,即使光标关闭,它似乎仍然可以使用。

我想这不是一种安全的方法,因为我怀疑在某些时候 gc 会使快照无效。

我仍然对在特定事务中使用的游标可以使用多长时间感到有些困惑,而且我无法在文档中找到答案。

下面是 Clojure 中的一个示例,展示了在事务完成和重新分配键之后,游标仍可用于检索数据的事实。

使用 xodus 1.3.232。

(ns chat-bot.xodus-cursor
  (:import [jetbrains.exodus.env Environments StoreConfig TransactionalComputable]
           [jetbrains.exodus.bindings IntegerBinding]))

(def store-name "test")

(defn startup []
  (Environments/newInstance "cursor-test"))

(defn shutdown [env]
  (.close env))

(defn fill [env n base]
  (.computeInTransaction
    env
    (reify TransactionalComputable
      (compute [this txn]
        (let [store (.openStore env store-name StoreConfig/WITHOUT_DUPLICATES txn)]
          (doseq [k (range n)]
            (.put store txn (IntegerBinding/intToEntry k) (IntegerBinding/intToEntry (+ base k)))))))))

(defn lazy-cursor [txn cursor has-next]
  (lazy-seq
    (when has-next
      (let [kv [(IntegerBinding/entryToInt (.getKey cursor)) (IntegerBinding/entryToInt (.getValue cursor))]]
        (println "realized" kv "txn finished" (.isFinished txn))
        (cons kv (lazy-cursor txn cursor (.getNext cursor)))))))

(defn get-seq [env]
  (.computeInReadonlyTransaction
    env
    (reify TransactionalComputable
      (compute [this txn]
        (let [store (.openStore env store-name StoreConfig/WITHOUT_DUPLICATES txn)]
          (with-open [cursor (.openCursor store txn)]
            (lazy-cursor txn cursor (.getNext cursor))))))))

(defn do-it []
  (let [env (startup)]
    (fill env 5 0) ;; put some data into the store
    (let [kvs0 (get-seq env)] ;; get the data sequence, not realized yet
      (fill env 5 10) ;; override the data
      (let [kvs1 (get-seq env)] ;; get the data sequence again
        (shutdown env)
        [kvs0 kvs1])))) ;; return both original and overridden data sequence


输出将是

(def s (do-it))  ;; sequences are still not realized

s  ;; output sequences to realize them

realized [0 0] txn finished true
realized [1 1] txn finished true
realized [2 2] txn finished true
realized [3 3] txn finished true
realized [4 4] txn finished true
realized [0 10] txn finished true
realized [1 11] txn finished true
realized [2 12] txn finished true
realized [3 13] txn finished true
realized [4 14] txn finished true
=> [([0 0] [1 1] [2 2] [3 3] [4 4]) ([0 10] [1 11] [2 12] [3 13] [4 14])]

;; the original and the re-assigned key/value sequence is returned

标签: clojurexodus

解决方案


只要您愿意,只要您在一段时间后最终完成(中止)它们,您就可以保持只读事务未完成。未完成的事务防止删除数据库 GC 移动的旧数据。因此,您可以保持事务未完成的时间取决于您的工作量:写入负载越大,时间越短。例如,如果在几个小时内没有那么多写入并且数据库大小增加了 1-2-3%,那么您可以将只读事务保持几个小时而不会对性能产生任何影响。唯一的缺点是如果您的应用程序无法正常关闭数据库,那么在下一次启动时它将从头开始计算文件利用率,即它将在后台遍历整个数据库。


推荐阅读