Why is MagmaSession>>#noteOldKeysFor: necessary?

Bart Gauquie bart.gauquie at gmail.com
Sat Jan 2 18:11:49 UTC 2010


Dear all,

I'm using Magma and finding out how transparent it can be. I'm trying Magma
to see if the DDD principles can be applied to it. To retrieve, store and
save aggegrate root objects a Repository object is used. A 'transient'
Repository object is nothing more than a wrapper around an
OrderedCollection, which contains store save and find methods. The client
who is using this Repository object does not know which implementation is
behind it. After retrieving the initial root aggegrate the client can
manipulate the sub objects of the aggegrate root.

I managed to achieve Read Transparency. I specialised the Repository objects
so they use a MagmaCollection instead of an ordinary OrderedCollection.  You
just do a findXXX method on the Repository, and that method is delegated to
a MagmaCollection which does a read based on some defined index.

To do a Write Transparency, I added a decorator around the store / save
methods of the Repository which automatically wraps the original Repository
object in a session commit:[] block; enabling Magma to see the changes made
to the 'saved' object and get them persisted.
AddTransactionAroundMutators>>doesNotUnderstand: aMessage
   |result|
     (self isMutator: aMessage)
      ifTrue: [repositoriesController commit:
        [result := aMessage sendTo: decorated]]
      ifFalse: [result := aMessage sendTo: decorated].
    ^result.
In which AddTransactionAroundMutators is a decorator around the Repository
object.

Persisting works, however I noticed that the hash indexes did not get
updated this way. On the wiki it is mentioned that
MagmaSession>>#noteOldKeysFor: should be called before any change to the
object is made. This is off course, using my idiom, impossible to do, since
the user using the Repository does not even know that there is a
MagmaSession. It just knows the API of the Repository object. The Seaside
GUI I'm using is manipulating an object (which it got from a findXXX query
on a repository) directly and if it wants to save the changes it calls
Repository>>save (which got decorated). The GUI using the Repositories does
not know Magma and I tend to keep it that way.

After some searching, I managed to circumvent this by a dirty hack:
AddTransactionAroundMutators>>doesNotUnderstand: aMessage
   |result|
   (self isMutator: aMessage)
      ifTrue: [
         (self isUpdatingMutator: aMessage) "denotes saveXXX methods =>
updates to existing objects"
           ifTrue: [
              |session session2 firstArg oidForFirstArg reReadObject|
               session := repositoriesController session.
               session2 := repositoriesController session2.
               firstArg := aMessage arguments first.
               oidForFirstArg := session oidFor: firstArg.
               reReadObject := session2 realObjectFor: oidForFirstArg.
               repositoriesController commit:
                   [session noteOldKeysFor: firstArg usingHashesFromObject:
reReadObject.
                     result := aMessage sendTo: decorated]]
           ifFalse: [
              repositoriesController commit:
               [result := aMessage sendTo: decorated]]]
      ifFalse: [result := aMessage sendTo: decorated].
^result.


MagmaSession>>noteOldKeysFor: anObject usingHashesFromObject: anOtherObject
   guard critical: [
           transaction ensureOldHashesCapturedFor: anObject
usingHashesFromObject: anOtherObject]

MaTransaction>>ensureOldHashesCapturedFor: anObject usingHashesFromObject:
anOtherObject
   (potentialKeysChange includesKey: anObject) ifTrue: [ ^ self ].
   self captureOldHashesFor: anObject usingHashesFromObject: anOtherObject

MaTransaction>>captureOldHashesFor: anObject usingHashesFromObject:
anOtherObject
   largeCollectionChanges do:
     [ :eachChanges |
       (eachChanges collection canIndex: anObject)
         ifTrue:
           [ eachChanges collection indexesDo:
                [ :eachIndex | | oldKeys oldHashes |
                    oldKeys := potentialKeysChange
                          at: anObject ifAbsentPut: [ IdentityDictionary new
].
                    oldHashes := oldKeys
                          at: eachIndex attribute ifAbsentPut: [
OrderedCollection new ].
                    oldHashes
                          add: { eachChanges. eachIndex. eachIndex
indexHashesFor: anOtherObject } ] ] ].

So I'm using a second MagmaSession to reload the object I'm about to commit
and I'm noting to the first session to noteOldKeysFor: anObject
usingHashingFromObject: theJustReloadedObjectFromTheSecondSession. Like
this, the first session gets the hashes of the unmodified object in the
repository, and the hashes get updated correctly automatically. It is a
working solution (at least with my very limited testing), but I find it very
complicated. Surely there must be a cleaner way to do an automatic hashkey
update.

Other things I already tried is to enable WriteBarrier, but could not get
that working.
I also tried to do readRealObject: oid on the same session; but this always
returned a cached version, with the already updated fields in. The only
thing that worked was to create a new session and make sure that the object
is fresh.

Can anyone help me on this one? I'm finding it a bit strange that Magma can
correctly save my changes, but not determine if a hash key update is
necessary.

Thanks for any help.

Kind Regards,

Bart

-- 
imagination is more important than knowledge - Albert Einstein
Logic will get you from A to B. Imagination will take you everywhere -
Albert Einstein
Learn from yesterday, live for today, hope for tomorrow. The important thing
is not to stop questioning. - Albert Einstein
The true sign of intelligence is not knowledge but imagination. - Albert
Einstein
However beautiful the strategy, you should occasionally look at the results.
- Sir Winston Churchill
It's not enough that we do our best; sometimes we have to do what's
required. - Sir Winston Churchill
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/magma/attachments/20100102/811f8612/attachment.htm


More information about the Magma mailing list