https://github.com/hiredman/clojure/compare/master...apocrypha-stm#L0L296

I've been playing around with the stm, and I think this change gives
you the behavior that is intuitively expected, someone else will have
to speak for correctness. ant test runs successfully but I don't know
how extensive the stm tests are.

I think the ping ponging arises because both transactions race to
acquire the write lock. Seems odd to me that it would ping pong so
regularly, but it is a concurrent program, so who knows.

Having the first writer lock may be an attempt to ensure that at least
one transaction can complete without retries.

On Mon, Aug 29, 2011 at 6:42 PM, Kevin Downey <redc...@gmail.com> wrote:
> weird, it actually ping-pongs, every other run of the (time …) the
> transaction in the future locks the ref writing so you get
>
> "Elapsed time: 10006.505 msecs"
> "Elapsed time: 0.358 msecs"
> "Elapsed time: 9038.18 msecs"
> "Elapsed time: 0.348 msecs"
> "Elapsed time: 26250.854 msecs"
>
> On Mon, Aug 29, 2011 at 6:13 PM, Kevin Downey <redc...@gmail.com> wrote:
>> https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LockingTransaction.java#L424
>> is definitely the line that causes the write lock to be acquired.
>>
>> I get the same behavior on master(1.3) and 1.2.1:
>>
>> the first time I run the code on a particular ref it locks for writing
>> while the first transaction is running, but subsequent runs do not.
>>
>> 1.3
>>
>> user=> (def x (ref 0))
>> #'user/x
>> user=> (time (do (future (dosync (alter x inc) (Thread/sleep 10000)))
>> (dosync (alter x dec))))
>> "Elapsed time: 10007.789 msecs"
>> 0
>> user=> (time (do (future (dosync (alter x inc) (Thread/sleep 10000)))
>> (dosync (alter x dec))))
>> "Elapsed time: 0.409 msecs"
>> -1
>> user=>
>>
>> 1.2
>>
>> Clojure 1.2.1
>> user=> (def x (ref 0))
>> #'user/x
>> user=> (time (do (future (dosync (alter x inc) (Thread/sleep 10000)))
>> (dosync (alter x dec))))
>> "Elapsed time: 10007.026 msecs"
>> 0
>> user=> (time (do (future (dosync (alter x inc) (Thread/sleep 10000)))
>> (dosync (alter x dec))))
>> "Elapsed time: 0.391 msecs"
>> -1
>> user=>
>>
>>
>> if I had to guess, I'd say that until a ref has some initial number of
>> history entries (1?) to satisfy readers it falls back to locking, but
>> I really have no clue
>>
>> On Mon, Aug 29, 2011 at 4:03 PM, Laurent PETIT <laurent.pe...@gmail.com> 
>> wrote:
>>> 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?
>>
>
>
>
> --
> And what is good, Phaedrus,
> And what is not good—
> Need we ask anyone to tell us these things?
>



-- 
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

Reply via email to