A read fault occurs when a transaction tries to use a stale ref value. The STM rejects that read and restarts the transaction so it can observe the current committed value. section 14.4
Read-fault behavior depends on the ref’s history policy:
- With the default zero history, a slow reader cannot use a value overwritten before its read completes; the transaction retries. section 14.4
- With positive min-history, a ref can retain in-transaction values and tolerate some stale reads without restarting. section 14.4
- ref-min-history configures this tolerance, while ref-max-history limits how many values the ref stores. section 14.4
A slow reader retries
A transaction T1 reads ref r, sleeps, and then encounters a value committed by faster transaction T2. With the default history, T1 starts twice and ultimately returns 1 rather than stale value 0. Setting :min-history 1 allows the reader to return 0 while r has become 1. section 14.4
(let [r (ref 0) ; #1
T1 (future ; #2
(dosync
(println "T1 starts")
(Thread/sleep 1000)
(println "T1 history-count"
(ref-history-count r))
@r))
T2 (future
(dosync
(println "T2 starts")
(alter r inc)))] ; #3
[@T1 @T2 @r])
;; T1 starts
;; T2 starts
;; T1 history-count 0 ; #4
;; T1 starts ; #5
;; T1 history-count 0
;; [1 1 1]
Inspect the concurrent futures example to see the retry in its printed output. section 14.4
