Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Commit loops

The store’s mutable cell is a hash. Wrap it once:

(def r (v/root-ref rs))
SituationOp
Read current valueref-deref (nil if unset)
Local single writerref-reset!
Might race (HTTP, two processes)ref-swap!
Seed empty remoteref-cas! from nil
Show conflict costref-swap-info!{:value :retries}

ref-reset! throws on a remote store. Seeding:

(or (v/ref-deref r)
    (let [seed (v/hash-map-via r "theme" "dark")]
      (v/ref-cas! r nil seed)
      seed))

ref-swap! is read → apply f → CAS. If another writer landed first, f runs again on the new current value. Domain functions must be retries-safe: compute the next value from the argument, do not close over a stale copy.

(v/ref-swap! r add-todo "milk")
;; add-todo is (fn [todos title] (v/conj todos …))

Two HTTP clients appending an event log use this loop; :retries is the UX when they collide. See Two writers, one CAS.

On write-back HTTP, ref-swap! / remote CAS flushes packed nodes, then CAS the root. Domain code does not call flush-from!.