Resend because of scrubbing of list ... <br><br><div class="gmail_quote">On Tue, Dec 8, 2009 at 9:18 PM, Bart Gauquie <span dir="ltr">&lt;<a href="mailto:bart.gauquie@gmail.com">bart.gauquie@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;"><div>Dear all,<br clear="all"></div><div><br></div><div>I&#39;ve been trying out the MagmaCommitConflictError in Magma. I&#39;m experiencing following which I do not understand. </div>
<div>I&#39;ve attached a changeset with a test case reproducing the behaviour I do not understand.</div>


<div><br></div><div>If I follow the steps outlined at: <a href="http://wiki.squeak.org/squeak/2636" target="_blank">http://wiki.squeak.org/squeak/2636</a><b> </b>a MagmaCommitConflictError is thrown.</div><div>(see testTriggerACommitConflictSequenceAsDescribedOnWiki and a little modification on that: testTriggerACommitConflictLoadObjectBeforeStartingATransaction)</div>



<div><br></div><div>If I however execute </div><div><br></div><div>testTriggerACommitConflictUsersCommitAfterEachOtherButWithTheSameVersionOfObjectInitiallyLoaded<br>        </div><div><br></div><div>|firstSession secondSession mockObjectRefByFirstSession mockObjectRefBySecondSession|<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>                firstSession commit. &quot;4. User 1 commits his transaction.&quot;<br><br>                secondSession begin. &quot;2. User 2 begins a transaction.&quot;<br>



                mockObjectRefBySecondSession aField: &#39;aField updated by user 2&#39;. &quot;5. User 2 changes Object A.&quot;<br>                <br>                self should: [secondSession commit. &quot;6.7. User 2 commits his transaction&quot;]<br>                        raise: MagmaCommitConflictError.<br>



                        </div><div><br></div><div>firstSession refresh.</div><div><br></div><div>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>        <br>It failes and I dont understand why. The test is what you get in a typical web application. User 1 has a session on the database. User 2 has another session. Both opened an item. Both are editing it and then first user1 commits his changes. User 2 wants to commit his changes but did not see the updated data of User 1. The test failes at : </div>


<div><br></div><div>self should: [secondSession commit. &quot;6.7. User 2 commits his transaction&quot;] raise: MagmaCommitConflictError. </div><div><br></div><div>=&gt; MagmaCommitConflictError is not thrown. Which is something I do not understand. User 2 is trying to commit a change on an object some other session already changed. So User 2 is trying to update a stale version. Is there a reason why no MagmaCommitConflictError is thrown? Furthermore, if you proceed on the failing MagmaCommitConflictError; refresh the firstSession; i notice that the changes made by Session2 effectively got committed; which surprises me even more. Because that means that the changes made by User 1 got overridden by the changes of User 2 without User 2 even knowing.</div>



<div><br></div><div>If I read the information on the wiki, this behaviour is correct since Magma will only detect if during a transaction (after begin has been called) some other session has committed changes on the object being changed. Off course this is not the kind of behaviour you have if you&#39;re developing web applications since there, the transactions are very short.</div>



<div><br></div><div>Is there a way to detect if an object was updated by another transaction, but not within my own transaction; so that stale updates do not happen. I suppose there is some version on a persisted object you can check and if the last committed version of an object is higher than the version in the current session, this also means a magmacommitconflicterror? But I havent found any info about that yet?</div>



<div><br></div><div>Thanks for any help.</div><div><br></div><div>Kind Regards,</div><div><br></div><div>Bart</div><br></blockquote></div><div><br></div><div>Attachment:<br></div><div><br></div><div>&#39;From Pharo1.0rc1 of 19 October 2009 [Latest update: #10493] on 8 December 2009 at 9:10:53 pm&#39;!<br>
TestCase subclass: #BMTTryingToUnderstandMagmaCommitConflictsTest<br>        instanceVariableNames: &#39;magmaServerConsole&#39;<br>        classVariableNames: &#39;&#39;<br>        poolDictionaries: &#39;&#39;<br>        category: &#39;BkbagMagmaTesting-Model-Magma-IntegrationTests&#39;!<br>
Object subclass: #SomeMockDomainObject<br>        instanceVariableNames: &#39;aField&#39;<br>        classVariableNames: &#39;&#39;<br>        poolDictionaries: &#39;&#39;<br>        category: &#39;BkbagMagmaTesting-Model-Magma-IntegrationTests&#39;!<br>
<br>!BMTTryingToUnderstandMagmaCommitConflictsTest methodsFor: &#39;tests&#39; stamp: &#39;TestRunner 12/8/2009 20:19&#39;!<br>testTriggerACommitConflictLoadObjectBeforeStartingATransaction<br>        |firstSession secondSession mockObjectRefByFirstSession mockObjectRefBySecondSession|<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>
                secondSession begin. &quot;2. User 2 begins a transaction.&quot;<br>                <br>                mockObjectRefByFirstSession aField: &#39;aField updated by user 1&#39;. &quot;3. User 1 changes Object A.&quot;<br>                firstSession commit. &quot;4. User 1 commits his transaction.&quot;<br>
                <br>                mockObjectRefBySecondSession aField: &#39;aField updated by user 2&#39;. &quot;5. User 2 changes Object A.&quot;<br>                <br>                self should: [secondSession commit. &quot;6.7. User 2 commits his transaction&quot;]<br>                        raise: MagmaCommitConflictError.<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>        <br>        <br>        ! !<br><br>!BMTTryingToUnderstandMagmaCommitConflictsTest methodsFor: &#39;tests&#39; stamp: &#39;TestRunner 12/8/2009 20:17&#39;!<br>testTriggerACommitConflictSequenceAsDescribedOnWiki<br>
        |firstSession secondSession mockObjectRefByFirstSession mockObjectRefBySecondSession|<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>                firstSession begin. &quot;1. User 1 begins a transaction.&quot;<br>
                secondSession begin. &quot;2. User 2 begins a transaction.&quot;<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>                mockObjectRefByFirstSession aField: &#39;aField updated by user 1&#39;. &quot;3. User 1 changes Object A.&quot;<br>                firstSession commit. &quot;4. User 1 commits his transaction.&quot;<br>                <br>                mockObjectRefBySecondSession aField: &#39;aField updated by user 2&#39;. &quot;5. User 2 changes Object A.&quot;<br>
                <br>                self should: [secondSession commit. &quot;6.7. User 2 commits his transaction&quot;]<br>                        raise: MagmaCommitConflictError.<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>        <br>        <br>        ! !<br><br>!BMTTryingToUnderstandMagmaCommitConflictsTest methodsFor: &#39;tests&#39; stamp: &#39;TestRunner 12/8/2009 20:47&#39;!<br>
testTriggerACommitConflictUsersCommitAfterEachOtherButWithTheSameVersionOfObjectInitiallyLoaded<br>        |firstSession secondSession mockObjectRefByFirstSession mockObjectRefBySecondSession|<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>                firstSession commit. &quot;4. User 1 commits his transaction.&quot;<br>
<br>                secondSession begin. &quot;2. User 2 begins a transaction.&quot;<br>                mockObjectRefBySecondSession aField: &#39;aField updated by user 2&#39;. &quot;5. User 2 changes Object A.&quot;<br>                <br>                self should: [secondSession commit. &quot;6.7. User 2 commits his transaction&quot;]<br>
                        raise: MagmaCommitConflictError.<br>                        <br>                firstSession refresh.<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>        <br>        <br>        ! !<br><br>!BMTTryingToUnderstandMagmaCommitConflictsTest methodsFor: &#39;running&#39; stamp: &#39;TestRunner 12/8/2009 19:49&#39;!<br>setUp<br>        super setUp.<br>        self ensureRepositoryCreated.<br>
        magmaServerConsole := <br>                 MagmaServerConsole new<br>                    open: self databasePath;<br>                     processOn: self databasePort;<br>                  yourself.<br>        <br>        ! !<br><br>!BMTTryingToUnderstandMagmaCommitConflictsTest methodsFor: &#39;running&#39; stamp: &#39;TestRunner 12/8/2009 16:21&#39;!<br>
tearDown<br>        super tearDown.<br>        magmaServerConsole shutdown.! !<br><br>!BMTTryingToUnderstandMagmaCommitConflictsTest methodsFor: &#39;helper&#39; stamp: &#39;TestRunner 12/8/2009 16:20&#39;!<br>databasePath<br>        ^&#39;tryingToUnderStandMagmaCommitConflicts&#39;! !<br>
<br>!BMTTryingToUnderstandMagmaCommitConflictsTest methodsFor: &#39;helper&#39; stamp: &#39;TestRunner 12/8/2009 16:26&#39;!<br>databasePort<br>        ^55789<br>        <br>        ! !<br><br>!BMTTryingToUnderstandMagmaCommitConflictsTest methodsFor: &#39;helper&#39; stamp: &#39;TestRunner 12/8/2009 16:21&#39;!<br>
ensureRepositoryCreated<br>        ((FileDirectory forFileName: &#39;&#39;) directoryExists: self databasePath)<br>        ifFalse: <br>                [MagmaRepositoryController<br>                            create: self databasePath<br>                    root: Dictionary new].        ! !<br>
<br><br>!SomeMockDomainObject methodsFor: &#39;accessing&#39; stamp: &#39;TestRunner 12/8/2009 16:24&#39;!<br>aField<br>        ^ aField! !<br><br>!SomeMockDomainObject methodsFor: &#39;accessing&#39; stamp: &#39;TestRunner 12/8/2009 16:24&#39;!<br>
aField: anObject<br>        aField := anObject! !<br><br>BMTTryingToUnderstandMagmaCommitConflictsTest removeSelector: #testTriggerACommitConflict!<br>BMTTryingToUnderstandMagmaCommitConflictsTest removeSelector: #testTriggerACommitConflict2!<br>
<br>!BMTTryingToUnderstandMagmaCommitConflictsTest reorganize!<br>(&#39;tests&#39; testTriggerACommitConflictLoadObjectBeforeStartingATransaction testTriggerACommitConflictSequenceAsDescribedOnWiki testTriggerACommitConflictUsersCommitAfterEachOtherButWithTheSameVersionOfObjectInitiallyLoaded)<br>
(&#39;running&#39; setUp tearDown)<br>(&#39;helper&#39; databasePath databasePort ensureRepositoryCreated)<br>!<br><br><br></div>