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