Changing objects in Magma
Last updated at 8:40 pm UTC on 22 March 2006
Magma utilizes a simple transaction protocol to isolate a batch of object changes that can be saved as a whole or canceled as a whole.
The three important messages of the transaction protocol are:
- begin - refresh from the repository and note the state of all persistent objects in memory.
- commit - compare all persistent objects to their noted "backup" copy, submit the changed ones to the server.
- abort - refresh from the repository.
These messages are sent to a MagmaSession.
Essentials of transactions
When a program executes any of these messages, it is said to be "crossing a transaction boundary," and is the time when the objects in the local image are sync'ed up with the Magma repository. All changes committed by other users since your last crossing immediately become visible to your program. For a commit, all individual changes made in your image are saved to the repository and will become visible to all other users as soon as they cross their next transaction boundary.
It may seem evident that, with correct timing of events, one user would be able to overlay changes made by another user. For example, consider the following scenario:
- User 1 begins a transaction.
- User 2 begins a transaction.
- User 1 changes Object A.
- User 1 commits his transaction.
- User 2, cannot yet see User 1's changes, because she has not crossed a transaction boundary since the commit.
- User 2 changes Object A.
- User 2 commits.
Thankfully, Magma will detect this conflict and signal a MagmaCommitError back to user 2. This is because she tried to change an object that was changed by User 1 since she began her transaction, invalidating her changes. The failed result object has the challenging objects that were in conflict (Object A) and the name of each user who changed them (User 1). Additionally, User 2 can now see the new Object A, as changed by User 1, because her commit attempt caused a crossing of a transaction boundary.
At this point, User 2 no longer has a transaction. She must reapply her changes under a new transaction, if appropriate.
Nested Transactions
Magma allows you to say:
mySession commit:
[ ...make some changes...
mySession commit: [ ...make some other changes... ] ]
The inner-commit actually does nothing; only the outer-commit writes all changes to the db. This is to support the requirement that a bank withdrawal be its own usable operation, a bank deposit be its own usable operation, but also transfer from one account to another (which uses the withdrawal code followed by deposit code) to only be committed wholly. You can just use #commit: in all three methods and it will only consider the outermost commit the one that really commits to the database.
See also:
Minmizing concurrency in Magma