Right, it's "according to the spec", but it doesn't explain the
behavior. as I noticed this morning http://clojure.org/refs references
http://en.wikipedia.org/wiki/Multiversion_concurrency_control (the
technique used to implement STM) which provides an explanation for the
experienced behavior:

<quote>
If a transaction (Ti) wants to write to an object, and if there is
another transaction (Tk), the timestamp of Ti must precede the
timestamp of Tk (i.e., TS(Ti) < TS(Tk)) for the object write operation
to succeed. Which is to say a write cannot complete if there are
outstanding transactions with an earlier timestamp.
</quote>

That's why the second transaction, which comes later in time, is the
one waiting for the first transaction to complete.

Dominikus

On Aug 30, 9:53 am, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> 2011/8/30 Kevin Downey <redc...@gmail.com>
>
> > the two threads race to acquire the write lock and the winner runs,
> > the loser retries. my guess is acquiring the write lock helps avoid
> > live locks between transactions.
>
> Yes, and after re-readinghttp://clojure.org/refs, the current behaviour
> does not seem to violate any of the 10 guaranteed listed points.
>
> So, while it seems unfortunate from client's code point of view, it is
> correct wrt to "the current specs".
>
> Now I more deeply understand why one should at all price avoid long
> computations from within a transaction ...
>
> Cheers,
>
> --
> Laurent
>
>
>
>
>
>
>
>
>
> > On Mon, Aug 29, 2011 at 10:59 PM, Laurent PETIT <laurent.pe...@gmail.com>
> > wrote:
> > > My tests were false.
> > > Since I sent the code "at once" to the REPL, there was a race condition
> > > between the start of the agent and the dosync for setting the ref's value
> > to
> > > 2000 ; this explains the weirdness of my test results (thank you, Mr
> > Murphy,
> > > for having made the tests look like beta2 behaved differently from the
> > > others ...)
> > > So now I see consistent behaviours across 1.2.0, beta1 and beta2.
> > > But I am still perplex and confused by the behaviour ...
>
> > > 2011/8/30 Laurent PETIT <laurent.pe...@gmail.com>
>
> > >> ok so now i'm totally confused, since I cannot see why the behaviour is
> > so
> > >> different between beta1 and beta 2 ...
>
> > >> 2011/8/30 Laurent PETIT <laurent.pe...@gmail.com>
>
> > >>> Congratulations, you've found a bug in clojure 1.3 beta2, see:
> > >>>  look with my clojure 1.2.0 version :
> > >>> ;; Clojure 1.2.0
> > >>> => (def thread (agent "Thread"))
> > >>>    (def account (ref 1000))
> > >>>    (send thread
> > >>>          (fn [agt aref] (dosync (alter aref + 100) (Thread/sleep 8000)
> > >>> agt))
> > >>>          account)
> > >>>    (time (dosync (ref-set account 2000)))
> > >>> #'user/thread
> > >>> #'user/account
> > >>> #<Agent@7e543cb1: "Thread">
> > >>> "Elapsed time: 0.498106 msecs"
> > >>> 2000
> > >>> => ;; 10 seconds later :
> > >>> => @account
> > >>> 2100
>
> > >>> And now with clojure 1.3 beta1 :
> > >>> ;; Clojure 1.3.0-beta1
> > >>> => (def thread (agent "Thread"))
> > >>>    (def account (ref 1000))
> > >>>    (send thread
> > >>>          (fn [agt aref] (dosync (alter aref + 100) (Thread/sleep 8000)
> > >>> agt))
> > >>>          account)
> > >>>    (time (dosync (ref-set account 2000)))
> > >>>    ;; 10 seconds later :
> > >>> #'user/thread
> > >>> #'user/account
> > >>> #<Agent@6bf51e5c: "Thread">
> > >>> "Elapsed time: 0.270225 msecs"
> > >>> 2000
> > >>> => @account
> > >>> 2100
> > >>> And now with Clojure 1.3-beta2
> > >>> ;; Clojure 1.3.0-beta2
> > >>> => (def thread (agent "Thread"))
> > >>>    (def account (ref 1000))
> > >>>    (send thread
> > >>>          (fn [agt aref] (dosync (alter aref + 100) (Thread/sleep 8000)
> > >>> agt))
> > >>>          account)
> > >>>    (time (dosync (ref-set account 2000)))
> > >>> #'user/thread
> > >>> #'user/account
> > >>> #<Agent@50fba502: "Thread">
> > >>> "Elapsed time: 7957.328798 msecs"
> > >>> 2000
> > >>>    ;; 10 seconds later :
> > >>> => @account
> > >>> 2000
> > >>>    ;; 10 more seconds later :
> > >>> => @account
> > >>> 2000
> > >>> 2011/8/30 Laurent PETIT <laurent.pe...@gmail.com>
>
> > >>>> 2011/8/29 Dominikus <dominikus.herzb...@gmail.com>
>
> > >>>>> Thanks a lot for this detailed analysis and the pointers to the Java
> > >>>>> implementation, Stefan! That's excellent and very helpful.
>
> > >>>>> I still wonder, why the first transaction blocks write access. My
> > >>>>> overall understanding of the transaction system is that changes to
> > >>>>> referenced values remain in-transaction before committing them, a
> > >>>>> write-lock shouldn't be needed. I'm surprised, that the second
> > >>>>> transaction is the one who has to retry 71 times even though the
> > first
> > >>>>> transaction hasn't committed anything yet.
>
> > >>>> I must confess this behaviour also challenges my assumptions.
> > >>>> Does this work the same whatever the clojure version used ?
>
> > >>>>> Cheers,
>
> > >>>>> Dominikus
>
> > >>>>> P.S.: Thanks for the idea to use 'future' to spawn a thread!
>
> > >>>>> On Aug 29, 5:42 pm, Stefan Kamphausen <ska2...@googlemail.com>
> > wrote:
> > >>>>> > The call to alter already wrote to the Ref, this requires a
> > >>>>> > write-lock on
> > >>>>> > the ref (see LockingTransaction.java/doSet).  After that it sleeps
> > a
> > >>>>> > while
> > >>>>> > and gets to its commit phase.  The other transactions retries in
> > the
> > >>>>> > meantime.  Consider the following code, which introduces some atoms
> > >>>>> > for
> > >>>>> > counting the retries
>
> > >>>>> > (defn tz []
> > >>>>> >   (let [rr (ref 10)
> > >>>>> >         a1 (atom 0)
> > >>>>> >         a2 (atom 0)]
> > >>>>> >     (println "Starting future")
> > >>>>> >     (future
> > >>>>> >      (dosync
> > >>>>> >       (swap! a1 inc)
> > >>>>> >       (alter rr + 100)
> > >>>>> >       (Thread/sleep 8000)))
> > >>>>> >     (println "Sleeping a bit")
> > >>>>> >     (Thread/sleep 1000)
> > >>>>> >     (println "Another dosync")
> > >>>>> >     (time
> > >>>>> >      (dosync
> > >>>>> >       (swap! a2 inc)
> > >>>>> >       (ref-set rr 1)))
> > >>>>> >     [@rr @a1 @a2 (.getHistoryCount rr)]))
>
> > >>>>> > user> (tz)
> > >>>>> > Starting future
> > >>>>> > Sleeping a bit
> > >>>>> > Another dosync
> > >>>>> > "Elapsed time: 7001.554 msecs"
> > >>>>> > [1 1 71 0]
>
> > >>>>> > Note, how the 71 retries nice fit the approximately 7 seconds left
> > >>>>> > and the
> > >>>>> > 100 miliseconds time-out (LOCK_WAIT_MSECS)  for the lock used in
> > >>>>> > LockingTransaction.java/tryWriteLock.
>
> > >>>>> > Transactions with significantly different run-times should be
> > >>>>> > avoided,
> > >>>>> > although there is some point at which older transactions will get
> > >>>>> > their
> > >>>>> > turn.  This could be another explanation of the effect.  Take a
> > look
> > >>>>> > at the
> > >>>>> > barge-function in LockingTransaction.java
>
> > >>>>> > Hope this helps,
> > >>>>> > Stefan
>
> > >>>>> --
> > >>>>> You received this message because you are subscribed to the Google
> > >>>>> Groups "Clojure" group.
> > >>>>> To post to this group, send email to clojure@googlegroups.com
> > >>>>> Note that posts from new members are moderated - please be patient
> > with
> > >>>>> your first post.
> > >>>>> To unsubscribe from this group, send email to
> > >>>>> clojure+unsubscr...@googlegroups.com
> > >>>>> For more options, visit this group at
> > >>>>>http://groups.google.com/group/clojure?hl=en
>
> > > --
> > > You received this message because you are subscribed to the Google
> > > Groups "Clojure" group.
> > > To post to this group, send email to clojure@googlegroups.com
> > > Note that posts from new members are moderated - please be patient with
> > your
> > > first post.
> > > To unsubscribe from this group, send email to
> > > clojure+unsubscr...@googlegroups.com
> > > For more options, visit this group at
> > >http://groups.google.com/group/clojure?hl=en
>
> > --
> > And what is good, Phaedrus,
> > And what is not good—
> > Need we ask anyone to tell us these things?
>
> > --
> > You received this message because you are subscribed to the Google
> > Groups "Clojure" group.
> > To post to this group, send email to clojure@googlegroups.com
> > Note that posts from new members are moderated - please be patient with
> > your first post.
> > To unsubscribe from this group, send email to
> > clojure+unsubscr...@googlegroups.com
> > For more options, visit this group at
> >http://groups.google.com/group/clojure?hl=en

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to