clojure - 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
解决方案
只要您愿意,只要您在一段时间后最终完成(中止)它们,您就可以保持只读事务未完成。未完成的事务防止删除数据库 GC 移动的旧数据。因此,您可以保持事务未完成的时间取决于您的工作量:写入负载越大,时间越短。例如,如果在几个小时内没有那么多写入并且数据库大小增加了 1-2-3%,那么您可以将只读事务保持几个小时而不会对性能产生任何影响。唯一的缺点是如果您的应用程序无法正常关闭数据库,那么在下一次启动时它将从头开始计算文件利用率,即它将在后台遍历整个数据库。
推荐阅读
- php - 使用测试信用卡时 PHP Parse Cloud 和 Stripe 的问题
- wagtail - 如何在 Wagtail api 中创建写入服务?
- c++ - 按降序填充数组c ++不排序
- python - 顺序颠倒时如何理解嵌套列表的列表推导结果?
- python - 无法使用 pyautogui 选择文本
- haskell - Travis CI - 为 Haskell Stack 构建绕过 50m 超时
- usb - WebUSB 检测网页是否正在打开
- python - Python:将两个链接的列拆分为新行
- redirect - Vue:直接重定向到孩子,而父母有一个参数
- c - 将两个指针字符串连接在一起的函数