Я пишу программу clojure, которая использует STM. В настоящий момент я заполняю STM (используя refs) при запуске из базы данных, а затем асинхронно обновляю базу данных всякий раз, когда транзакция dosync завершается успешно. Я понятия не имею, правильно ли я делаю это правильно, или если для этого есть более стандартная техника. Может ли кто-нибудь объяснить мне, как они делают ACI-свойства STM в ACID в своих программах clojure?
Как я могу сделать программу STM clojure постоянной?
Ответ 1
В общем, добавление "D" в ACID в любую программу не является тривиальным и зависит от требований программы. Существует одна важная спецификация, которая должна быть определена до того, как можно будет определить реализацию.
Существует ли многопоточный/многопроцессный доступ к базе данных?
Из тела вопроса ваша программа, по-видимому, читает только при запуске и записывает после изменения STM, где база данных будет задерживать значения в STM на небольшое количество времени. Однако , если к базе данных обращаются другие программы, включая другие экземпляры вашей программы, тогда вам нужно будет использовать блокировки, где вы блокируете доступ к базе данных прямо перед транзакциями и разблокируете после записи в базы данных (в качестве примечания, обратите внимание, что база данных в вашем случае может быть любой, включая простой файл в файловой системе). Нет никакого способа обойти это, если у вас есть несколько операций чтения и записи, потому что они оба являются побочными эффектами, которые связаны с базой данных.
Если не существует множественного доступа, то асинхронная запись прекрасна, потому что гарантируется, что код всегда будет работать в порядке, так как ваша программа будет однопоточной, когда приходит доступ.
Если у вас есть только несколько потоков записи и без чтения после запуска только с одним экземпляром, вам нужно только обеспечить правильный порядок записи. Вы можете сделать это с помощью агентов, где агент в основном представляет собой очередь операций записи в базу данных. Вы переносите dosync вокруг ссылочных транзакций и агента, давая вам прочность в дополнение к постоянству.
В целом, чем сложнее требования, связанные с побочными эффектами, тем больше уловок вам нужно будет сделать для обеспечения ACID. Если у вас есть дополнительные требования, то реализация, которую я дал, может измениться.
EDIT:
(def db-agent (agent dummy-value))
(defn db-write [_ data] ;; make this intelligent to handle when db is not up
(try
(write-to-db data)
(catch ... database fails, do a retry or let user know of problem))
_)
;; in the transaction code
(dosync
(alter my-ref ...)
(send-off db-agent db-write @my-ref)) ;; ensure db gets written to
Ответ 2
Вам может быть интересно:
-
Alyssa Kwan модифицировал ядро Clojure, которое добавляет упорство в refs, см.: ИНС: Прочные рефов с кислыми гарантий - фаза I, ИНС: Прочный Clojure - Фаза II - Стойкие структуры данных, ИНС: Прочный Clojure - Функции и Затворы
-
Библиотека Сергея Диденко, которая не дает надежной гарантии долговечности, но довольно близка к таковой: Simple-Persistence-for-Clojure
Другие подходы могут быть не столь прозрачными для программиста.
Ответ 3
Модель STM очень хорошо подходит для отслеживания множественного доступа к системам по мере их изменения. Он менее точно подходит для сохранения данных, когда изменения должны быть доступны за пределы жизни потоков, которые обращаются к ним.
Как правило, хорошо думать о "D" в ACID отдельно от STM
Ответ 4
Если вам нужна база данных с быстрым доступом в памяти и время от времени сохраняется за кулисами, тогда используйте реальное хранилище данных, а не пытайтесь создать свой собственный, что будет довольно большой работой.
Redis и MongoDB - два хорошие варианты, но есть и многие другие. Библиотеки Clojure можно найти в https://github.com/ragnard/redis-clojure и https://github.com/somnium/congomongo для Redis и Mongo соответственно.