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

Reply via email to