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