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?

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