On Mon, Mar 15, 2010 at 8:44 AM, Mark Engelberg <[email protected]>wrote:
> Thanks Michal, those annotations helped quite a bit. It also demonstrates
> to me that my mental model of how the STM works is quite out of touch with
> how it actually does.
>
> I'm especially surprised that derefs work the way your example
> illustrates. From the STM docs, it really sounded like derefs always give
> you the value as of the snapshot from the start of the transaction. Your
> example also seems to violate this principle from the STM doc:
> "Writers will never block commuters, or readers."
>
> Your example shows that a write to a ref has effectively blocked (by
> forcing a retry) of a transaction which only reads the ref.
>
It hasn't blocked in the sense of "wait and continue": it retries the
transaction after growing the history of the ref (refs have an adaptive
history):
(defn funk [r]
(dosync
(println "1st read" @r)
(Thread/sleep 5000)
(println "2nd read" @r)))
user=> (def r (ref 1))
#'user/r
user=> (future (funk r))
1st read 1
#<core$future_call$reify__3...@64cc4d: :pending>
user=> (dosync (ref-set r 5))
5
1st read 5 ;; ok it's retrying
2nd read 5
;; let's try again:
user=> (dosync (ref-set r 1))
1
user=> (future (funk r))
1st read 1
#<core$future_call$reify__3...@1b993d6: :pending>
user=> (dosync (ref-set r 5))
5
2nd read 1 ;; no retry this time!
you can create a ref with a given minimal history:
user=> (def r (ref 1 :min-history 1))
#'user/r
user=> (future (funk r))
#<core$future_call$reify__3...@502a39: :pending>
1st read 1
user=> (dosync (ref-set r 5))
5
2nd read 1 ;; see, no retry
>From the end of (doc ref):
Normally refs accumulate history dynamically as needed to deal with
read demands. If you know in advance you will need history you can
set :min-history to ensure it will be available when first needed (instead
of after a read fault). History is limited, and the limit can be set
with :max-history.
If derefs really can force a retry, can't Meikel's example be rewritten
> without ensure by just deref-ing again at the end?...
>
> (dosync
> (when (= @reactor-state :off)
> (alter reactor-door open)
> @reactor-state))
>
>
No because once reactor-state has enough history it won't retry.
Even if you set :max-history to 0 it won't guarantee the retry because the
value of reactor-state can change between the last read and the moment the
commit is performed.
hth,
Christophe
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en