<div>Hi Chris,<br></div><div><br></div><div>That makes perfectly sense to me. </div><div><br></div><div>If I want to check that user 2 does not update a stale (which was updated by user 1) version; I should use a sort of pessimistic locking scheme, as described on the wiki. For instance:</div>
<div><br></div><div>&lt;code&gt;</div><div>testTriggerAVersionConflictByUsingVersionLogic<br>        |firstSession secondSession mockObjectRefByFirstSession mockObjectRefBySecondSession versionBeforeSessionBeginOfObjectReffedBySecondSession|<br>
        [firstSession :=<br>            (MagmaRemoteLocation<br>                      host: &#39;localhost&#39;<br>                       port: self databasePort) newSession.<br>                firstSession connectAs: &#39;firstSessionUser&#39;.<br>                firstSession commit: [<br>
                        firstSession root<br>                                at: &#39;mockObject&#39;<br>                                put: (SomeMockDomainObject new aField: &#39;aField content&#39;; yourself)].<br>                <br>                secondSession := <br>                        (MagmaRemoteLocation<br>                                host: &#39;localhost&#39;<br>
                                port: self databasePort) newSession.<br>                secondSession connectAs: &#39;secondSessionUser&#39;.<br><br>                mockObjectRefByFirstSession := firstSession root at: &#39;mockObject&#39;. &quot;User 1 is loading the object&quot;<br>
                mockObjectRefBySecondSession := secondSession root at: &#39;mockObject&#39;. &quot;User 2 is loading the same version of the object as User 1&quot;<br>                <br>                firstSession begin. &quot;1. User 1 begins a transaction.&quot;<br>
                mockObjectRefByFirstSession aField: &#39;aField updated by user 1&#39;. &quot;3. User 1 changes Object A.&quot;<br>                mockObjectRefByFirstSession incrementVersion.<br>                firstSession commit. &quot;4. User 1 commits his transaction.&quot;<br>
                <br>                versionBeforeSessionBeginOfObjectReffedBySecondSession := mockObjectRefBySecondSession version. &quot;retrieve version of object right before<br>                        beginning transaction (which does a refresh of the data of the object) - so also updates the version field, thats why we have to <br>
                        get the version right before beginning the transaction&quot;<br>                self assert: 0 equals: versionBeforeSessionBeginOfObjectReffedBySecondSession.<br>                secondSession begin. &quot;2. User 2 begins a transaction.&quot;        <br>
                self assert: 1 equals: mockObjectRefBySecondSession version. &quot;new version silently got merged in&quot;<br>                &quot;since versions are not equal =&gt; user 2 has been updating a stale version of object; so abort and do not commit any changes; <br>
                        and signal a ConcurrentModificationException to the client&quot;.<br>                mockObjectRefBySecondSession aField: &#39;aField updated by user 2&#39;. &quot;5. User 2 changes Object A.&quot;<br>                secondSession abort.<br>                <br>
                self assert: &#39;aField updated by user 1&#39; equals: ((firstSession root at: &#39;mockObject&#39;) aField).<br>                self assert: &#39;aField updated by user 1&#39; equals: ((secondSession root at: &#39;mockObject&#39;) aField).<br>
                self assert: &#39;aField updated by user 1&#39; equals: (mockObjectRefBySecondSession aField).<br><br>        ] ensure: [[firstSession commit: [<br>                                firstSession root removeAll].<br>                                firstSession disconnect] <br>                                        ensure: <br>
                                                [secondSession disconnect]]<br></div><div><br></div><div>&lt;/code&gt;</div><div><br></div><div>Are there any options in Magma provided to simulate such behavior automatically ?</div><div><br></div><div>Thanks again.</div>
<div><br></div><div>Kind Regards,</div><div><br></div><div>Bart</div><br><div class="gmail_quote">On Thu, Dec 10, 2009 at 8:44 PM, Chris Muller <span dir="ltr">&lt;<a href="mailto:asqueaker@gmail.com">asqueaker@gmail.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">Hi, the should: raise: MagmaCommitConflictError in<br>
#testTriggerACommitConflictUsersCommitAfterEachOtherButWithTheSameVersionOfObjectInitiallyLoaded<br>
:<br>
<div class="im"><br>
                self should: [secondSession commit. &quot;6.7. User 2 commits his transaction&quot;]<br>
                        raise: MagmaCommitConflictError.<br>
<br>
</div>fails because secondSession crossed a transaction boundary (via its<br>
#begin) after firstSession&#39;s commit.  Second session would see the<br>
results of firstSession&#39;s commit, and therefore there is no conflict.<br>
A commit-conflict would have occurred if secondSession had sent #begin<br>
BEFORE firstSession&#39;s commit..<br>
<br>
Regards,<br>
<div class="im">  Chris<br>
<br>
<br>
On Tue, Dec 8, 2009 at 2:18 PM, Bart Gauquie &lt;<a href="mailto:bart.gauquie@gmail.com">bart.gauquie@gmail.com</a>&gt; wrote:<br>
</div><div><div class="h5">&gt; Dear all,<br>
&gt;<br>
&gt; I&#39;ve been trying out the MagmaCommitConflictError in Magma. I&#39;m experiencing<br>
&gt; following which I do not understand.<br>
&gt; I&#39;ve attached a changeset with a test case reproducing the behaviour I do<br>
&gt; not understand.<br>
&gt; If I follow the steps outlined at:<br>
&gt; <a href="http://wiki.squeak.org/squeak/2636" target="_blank">http://wiki.squeak.org/squeak/2636</a> a MagmaCommitConflictError is thrown.<br>
&gt; (see testTriggerACommitConflictSequenceAsDescribedOnWiki and a little<br>
&gt; modification on that:<br>
&gt; testTriggerACommitConflictLoadObjectBeforeStartingATransaction)<br>
&gt; If I however execute<br>
&gt; testTriggerACommitConflictUsersCommitAfterEachOtherButWithTheSameVersionOfObjectInitiallyLoaded<br>
&gt;<br>
&gt; |firstSession secondSession mockObjectRefByFirstSession<br>
&gt; mockObjectRefBySecondSession|<br>
&gt; [firstSession :=<br>
&gt; (MagmaRemoteLocation<br>
&gt; host: &#39;localhost&#39;<br>
&gt; port: self databasePort) newSession.<br>
&gt; firstSession connectAs: &#39;firstSessionUser&#39;.<br>
&gt; firstSession commit: [<br>
&gt; firstSession root<br>
&gt; at: &#39;mockObject&#39;<br>
&gt; put: (SomeMockDomainObject new aField: &#39;aField content&#39;; yourself)].<br>
&gt;<br>
&gt; secondSession :=<br>
&gt; (MagmaRemoteLocation<br>
&gt; host: &#39;localhost&#39;<br>
&gt; port: self databasePort) newSession.<br>
&gt; secondSession connectAs: &#39;secondSessionUser&#39;.<br>
&gt;<br>
&gt; mockObjectRefByFirstSession := firstSession root at: &#39;mockObject&#39;. &quot;User 1<br>
&gt; is loading the object&quot;<br>
&gt; mockObjectRefBySecondSession := secondSession root at: &#39;mockObject&#39;. &quot;User 2<br>
&gt; is loading the same version of the object as User 1&quot;<br>
&gt;<br>
&gt; firstSession begin. &quot;1. User 1 begins a transaction.&quot;<br>
&gt; mockObjectRefByFirstSession aField: &#39;aField updated by user 1&#39;. &quot;3. User 1<br>
&gt; changes Object A.&quot;<br>
&gt; firstSession commit. &quot;4. User 1 commits his transaction.&quot;<br>
&gt;<br>
&gt; secondSession begin. &quot;2. User 2 begins a transaction.&quot;<br>
&gt; mockObjectRefBySecondSession aField: &#39;aField updated by user 2&#39;. &quot;5. User 2<br>
&gt; changes Object A.&quot;<br>
&gt;<br>
&gt; self should: [secondSession commit. &quot;6.7. User 2 commits his transaction&quot;]<br>
&gt; raise: MagmaCommitConflictError.<br>
&gt;<br>
&gt; firstSession refresh.<br>
&gt; self assert: &#39;aField updated by user 1&#39; equals: ((firstSession root at:<br>
&gt; &#39;mockObject&#39;) aField).<br>
&gt; self assert: &#39;aField updated by user 1&#39; equals: ((secondSession root at:<br>
&gt; &#39;mockObject&#39;) aField).<br>
&gt; self assert: &#39;aField updated by user 1&#39; equals:<br>
&gt; (mockObjectRefBySecondSession aField).<br>
&gt;<br>
&gt; ] ensure: [[firstSession commit: [<br>
&gt; firstSession root removeAll].<br>
&gt; firstSession disconnect]<br>
&gt; ensure:<br>
&gt; [secondSession disconnect]]<br>
&gt;<br>
&gt; It failes and I dont understand why. The test is what you get in a typical<br>
&gt; web application. User 1 has a session on the database. User 2 has another<br>
&gt; session. Both opened an item. Both are editing it and then first user1<br>
&gt; commits his changes. User 2 wants to commit his changes but did not see the<br>
&gt; updated data of User 1. The test failes at :<br>
&gt; self should: [secondSession commit. &quot;6.7. User 2 commits his transaction&quot;]<br>
&gt; raise: MagmaCommitConflictError.<br>
&gt; =&gt; MagmaCommitConflictError is not thrown. Which is something I do not<br>
&gt; understand. User 2 is trying to commit a change on an object some other<br>
&gt; session already changed. So User 2 is trying to update a stale version. Is<br>
&gt; there a reason why no MagmaCommitConflictError is thrown? Furthermore, if<br>
&gt; you proceed on the failing MagmaCommitConflictError; refresh the<br>
&gt; firstSession; i notice that the changes made by Session2 effectively got<br>
&gt; committed; which surprises me even more. Because that means that the changes<br>
&gt; made by User 1 got overridden by the changes of User 2 without User 2 even<br>
&gt; knowing.<br>
&gt; If I read the information on the wiki, this behaviour is correct since Magma<br>
&gt; will only detect if during a transaction (after begin has been called) some<br>
&gt; other session has committed changes on the object being changed. Off course<br>
&gt; this is not the kind of behaviour you have if you&#39;re developing web<br>
&gt; applications since there, the transactions are very short.<br>
&gt; Is there a way to detect if an object was updated by another transaction,<br>
&gt; but not within my own transaction; so that stale updates do not happen. I<br>
&gt; suppose there is some version on a persisted object you can check and if the<br>
&gt; last committed version of an object is higher than the version in the<br>
&gt; current session, this also means a magmacommitconflicterror? But I havent<br>
&gt; found any info about that yet?<br>
&gt; Thanks for any help.<br>
&gt; Kind Regards,<br>
&gt; Bart<br>
&gt; --<br>
&gt; imagination is more important than knowledge - Albert Einstein<br>
&gt; Logic will get you from A to B. Imagination will take you everywhere -<br>
&gt; Albert Einstein<br>
&gt; Learn from yesterday, live for today, hope for tomorrow. The important thing<br>
&gt; is not to stop questioning. - Albert Einstein<br>
&gt; The true sign of intelligence is not knowledge but imagination. - Albert<br>
&gt; Einstein<br>
&gt; Gravitation is not responsible for people falling in love. - Albert Einstein<br>
&gt;<br>
</div></div><div><div class="h5">&gt; _______________________________________________<br>
&gt; Magma mailing list<br>
&gt; <a href="mailto:Magma@lists.squeakfoundation.org">Magma@lists.squeakfoundation.org</a><br>
&gt; <a href="http://lists.squeakfoundation.org/mailman/listinfo/magma" target="_blank">http://lists.squeakfoundation.org/mailman/listinfo/magma</a><br>
&gt;<br>
&gt;<br>
</div></div></blockquote></div><br><br clear="all"><br>-- <br>imagination is more important than knowledge - Albert Einstein<br>Logic will get you from A to B. Imagination will take you everywhere - Albert Einstein<br>Learn from yesterday, live for today, hope for tomorrow. The important thing is not to stop questioning. - Albert Einstein<br>
The true sign of intelligence is not knowledge but imagination. - Albert Einstein<br>Gravitation is not responsible for people falling in love. - Albert Einstein<br>