commitUnitOfWorkAndCOntinue and rollbackUnitOfWorkAndContinue

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

commitUnitOfWorkAndCOntinue and rollbackUnitOfWorkAndContinue

jtuchel
As you may have read in my other post "Still struggling with the Simplest Transaction concepts", I am having problems with missed UPDATEs because of non-registered objects in a session.

The whole thing has a long history and I am circling around the very same kinds of problems, returning to the starting point over and over again.

As I wrote there, re-registering objects after a commitUnitOfWork does make sure that UPDATEs will be recognized.

Some of you may know that there even is a method in Glorp that is intended for exactly that purpose: committing or rolling back a UnitOfWork and making sure the objects are still correctly maintained in the image for the next  UnitOfWork. The methods are called

commitUnitOfWorkAndContinue
rollbackUnitOfWorkAndContinue

They are, unfortunately wrong and/or incomplete and I tried to fix them years ago, even discussing my attempt with Niall Ross at the ESUG in Cambridge. I finally gave up using them, because there still were some effects related to collections that I couldn't explain.

I will post my modified versions of the methods here, maybe somebody can take a look and give me feedback on what is missing in the case of Collections.

So here is the original version of commitUnitOfWorkAndContinue (taken from Cincom VisuelWorks 98.2):

GlorpSession>>commitUnitOfWorkAndContinue
    "Commit the current unit of work, but then keep going with the same set of registered objects, with their state updated to reflect current values."
    | registeredObjects |   
    currentUnitOfWork isNil ifTrue: [^self error: 'Not in unit of work'].
    registeredObjects := currentUnitOfWork registeredObjects.
    currentUnitOfWork deletedObjects do: [:each | registeredObjects remove: each].
    self commitUnitOfWork.
    self beginUnitOfWork.
    self registerAll: registeredObjects.


This does have problems with deleted objects in Collections (you could end up using deleted objects and get into real trouble on next commit), so I modified it to:

GlorpSession>>commitUnitOfWorkAndContinue
    "Commit the current unit of work, but then keep going with the same set of registered objects, with their state updated to reflect current values."

    | registeredObjects oldUnit |

    currentUnitOfWork isNil ifTrue: [^self error: 'Not in unit of work'].

    "Remove all collections, because they could contain deleted objects"
    registeredObjects :=
        (oldUnit := currentUnitOfWork) registeredObjects reject: [:each | each isCollection].

    self commitUnitOfWork.

    oldUnit deletedObjects do: [:del| registeredObjects remove: del ifAbsent: []].

    self beginUnitOfWork.
    self registerAll: registeredObjects



But I am not absolutely sure if it is sufficient to just throw away all Collections. It works much better than the original, but I ended up not using it any more because of problems I couldn't explain and because keeping all objects "forever" grows memory consumption significantly - not a great idea in a Web server.



For completeness, here is the original version of rollbackUnitOfWorkAndContinue from VisualWorks:

rollbackUnitOfWorkAndContinue
    "Rollback the current unit of work, but then keep going with the same set of existing objects (but not new ones) as were registered, with their state reverted to their at-registration state.  (If a user wants the newObjects, they can get them before sending #rollbackAndContinue, and then #registerAsNew: them after doing so.  That is their decision.)"

    | registeredObjects |   
    currentUnitOfWork isNil ifTrue: [^self error: 'Not in unit of work'].
    registeredObjects := currentUnitOfWork registeredObjects.
    currentUnitOfWork newObjects do: [:each | registeredObjects remove: each].
    self rollbackUnitOfWork.
    self beginUnitOfWork.
    self registerAll: registeredObjects.



And my "fixed" version of it:

rollbackUnitOfWorkAndContinue
    "Rollback the current unit of work, but then keep going with the same set of registered objects, with their state updated to reflect current values."

    | registeredObjects |
    registeredObjects := OrderedCollection new.
    currentUnitOfWork isNil
        ifFalse: [

            "Reject collections, because they could contain new objects that will not be inserted due to this rollback"
            registeredObjects :=
                currentUnitOfWork registeredObjects reject: [:each | each isCollection].

            currentUnitOfWork newObjects do: [:each | registeredObjects remove: each].
            self rollbackUnitOfWork].
    self beginUnitOfWork.
    self registerAll: registeredObjects


These two fixed methods have been in use in Kontolino! for about two years and the most important negative impact was the high memory consumption...
And, of course, the fact that one user completely misses new objects inserted by another user or deletes performed by another user. A user completely ignores what happens around in other sessions...
So we ripped them out, just to find out a few days ago that we miss updates (see my other post).


So maybe what is needed is a mix of commitUOWAndContinue and some kind of "starting from scratch" every x times. Or something completely different?

How do people manage their object caches in such a setting? What is your strategy for keeping up with things?


I look forward to reading about your experiences and ideas. And maybe somebody feels like looking at my changes to the ...AndContinue methods and comment on them.


Joachim
















--
You received this message because you are subscribed to the Google Groups "glorp-group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/glorp-group.
For more options, visit https://groups.google.com/d/optout.