[GemStone-Smalltalk] Transcient instance variable

Norm Green via GemStone-Smalltalk gemstone-smalltalk at lists.gemtalksystems.com
Tue Nov 11 08:30:18 PST 2014


Just FYI, GemStone/64 v3 does support nested transactions. See methods 
in class System. For example:

classmethod: System
beginNestedTransaction
"Enter a new nested transaction.
  If session is outside of a transaction, equivalent to beginTransaction.
  Signals a ImproperOperation exception if the begin would exceed16 
levels of nested transactions."


Norm



On 11/11/2014 8:16 AM, Paul Baumann via GemStone-Smalltalk wrote:
>
> Bob,
>
> I'm familiar with that approach. When you have an object-oriented 
> window style where you can open many editors on many objects at once 
> then it is easy to lament the absence of nested transactions. 
> Validation rules tend to be hard part; you want your object model to 
> participate in validation but the window needs to make the changes to 
> the domain for the domain to validate. Sometimes validation needs to 
> happen in both GS and VW. If you have more than simple data structures 
> (like a good object model) then validations are difficult. What you 
> end up doing is creating a framework that simulates nested 
> transactions. A different approach is to use a single managed window 
> (like a notebook) through which all changes are made in a way that 
> fits the traditional GS transaction model.
>
> The nested transaction functionality that I'd used (like 10 years ago) 
> would feed changes to the change manager of the active window. The 
> changes are applied to domain objects immediately for their 
> validation. A save of changes can be an abort, replay of changes, and 
> then commit. Each window is aware of its own pending changes and 
> replays changes as necessary for transaction changes. There are 
> probably many important details that I'm forgetting to describe, but 
> this approach was able to work. It sounds like your approach tries let 
> the window see changes on the domain objects that aren't quite there 
> yet. You are creating a generic form of an action model that 
> represents a future change. Like you said, large collections can be a 
> problem because it is the actions made to the collections that you 
> want to play and the generic means of capturing relies on observing 
> differences. I recall collections being a tricky part with the 
> approach that I'd used too. I suspect that collection changes were 
> made with the help of the change manager so that the change manager 
> could know the actions that caused the collection changes.
>
> Another way to simulate nested transactions is to use multiple gems. I 
> haven't tried that approach. If you use any (cached) forwarders then 
> GBS would throw errors. There was always too much risk of GBS bugs or 
> cache use restrictions. The well-travelled path is easier to follow; 
> unfortunately that means a window design that never has more than one 
> ongoing set of changes to manage. Consider a window change coordinator 
> that ensures that changes are either saved or aborted before you are 
> able to start making changes in a different window.
>
> Regards,
>
> Paul Baumann
>
> *From:*GemStone-Smalltalk 
> [mailto:gemstone-smalltalk-bounces at lists.gemtalksystems.com] *On 
> Behalf Of *via GemStone-Smalltalk
> *Sent:* Tuesday, November 11, 2014 09:29
> *To:* gemstone-smalltalk at lists.gemtalksystems.com
> *Subject:* Re: [GemStone-Smalltalk] Transcient instance variable
>
> Paul,
>
> Interesting idea: we do need the stored values since we do have domain 
> code that compares updated vs. original.
>
> I do have some concerns. Aside from having to deal with unintended 
> commits (as you mentioned), we would also add some complexity to our 
> development environment.
>
> Right now we're able use VW with an 'in-memory' domain model. Great 
> for debugging and SUnit tests.  The same domain code runs in the dev 
> VW image as in GS (the deployed web server image has no domain code). 
> If we update the domain instance in VW we'd have to unwind it in a 
> pseudo-abort.
>
> Storing the updates in a data wrapper is working well for us, since 
> the final 'save' is an explicit domain update. We can do a lot of 
> pre-save model validation. Each GS call is a RESTful call that 
> rebuilds the data wrapper model, makes updates, and sends the result. 
> All of which is done with no updates to domain objects until a 'save' 
> is done. Each call is wrapped in a 'current context' that holds all 
> the data wrappers, keyed so that we can find a corresponding wrapper 
> for a domain object.
>
> Most 'read' calls are now under 50ms.  Read + pending updates are 
> 100ms to 200ms, as are the saves. The problem is that some behaviours 
> reference large collections. In the past we wrapped every referenced 
> domain object if there were /any /pending updates. Now we only wrap 
> those with known pending updates. This introduced a heterogeneous 
> model with wrapped and unwrapped instances.
>
> Not a problem, but the code would be simpler if there were only domain 
> objects in mix (assuming the impact on performance was minimal). 
>  That's the change I'm looking at.  Right now I'm leaning towards a 
> 'dataWrapper' instVar on the domain root class that we would clear 
> prior to a commit. Having a notNil instVar during a read would be an 
> error condition.
>
> Bob
>
> On Monday, November 10, 2014 6:01 PM, Paul Baumann via 
> GemStone-Smalltalk <gemstone-smalltalk at lists.gemtalksystems.com 
> <mailto:gemstone-smalltalk at lists.gemtalksystems.com>> wrote:
>
> Hi Bob,
>
> It seems like you are currently thinking of using the dataWrapper to 
> note the new change. Consider if it will suit your needs better to use 
> your dataWrapper to note the values before the first inst var change 
> (like with a shallow copy), and allow the change to be made to the 
> inst vars. The shallowCopy can be registered in some manager and the 
> dataWrapper inst var of the copy can refer to the original object.
>
> assignDataWrapper
>
> dataWrapper isNil ifTrue: [
>
> dataWrapper := self copy.
>
> copy dataWrapper: self.
>
> (SessionTemps current at: #ChangeManager ifAbsentPut: [Array new])
>
>                 add: dataWrapper.
>
>                 ].
>
> ^dataWrapper
>
> foo: newValue
>
> self assignDataWrapper.
>
> foo := newValue
>
> foo
>
> ^foo
>
> This approach performs better because changes to objects are less 
> frequent than access to variables. The cost of making a change is the 
> creation of a copy and adding it to some managed collection. The code 
> needs to make consistent use of the custom setter methods, or else 
> you'd try to hook some generic object dirtying code.
>
> The ChangeManager can be defined however you want changes to survive. 
> You can detect changes both at the object level and by the manager. 
> You'd probably either do transaction changes through your 
> ChangeManager or notify the manager afterwards (note that 
> #continueTransaction has a notification bug). If your dataWrapper/copy 
> is a committed object then you'd know that an unmanaged commit 
> happened (the inst vars may now also contain changes from another 
> session). If ChangeManager has copies that differ from what the 
> originals noted for your session then you might have had an unmanaged 
> begin/abort/continue transaction.
>
> Regards,
>
> Paul Baumann
>
> *From:*GemStone-Smalltalk 
> [mailto:gemstone-smalltalk-bounces at lists.gemtalksystems.com] *On 
> Behalf Of *via GemStone-Smalltalk
> *Sent:* Monday, November 10, 2014 16:52
> *To:* gemstone-smalltalk at lists.gemtalksystems.com 
> <mailto:gemstone-smalltalk at lists.gemtalksystems.com>
> *Subject:* Re: [GemStone-Smalltalk] Transcient instance variable
>
> Paul,
>
> Thanks for the note on 'System rcValueCache'. I can see use using it 
> for other cases.
>
> For the 'data wrapper' code change I'm considering performance is 
> key. The check for updated values would be done on each in 'get' 
> method, so anything that slows that down would be noticeable.
>
> I was thinking of code like... (we're still brainstorming this)
>
> foo
>
> ^self getUpdatedValueAt: #foo with: foo
>
> getUpdatedValueAt: aKey with: aValue
>
> self dataWrapper isNil ifTrue: [^aValue].
>
> ^self dataWrapper getUpdatedValueAt: aKey with: aValue  "where aValue 
> is answered if there are no updates for2 #foo"
>
> ...we may just do this and take responsibility for clearing the data 
> wrapper instVar just prior to a commit.
>
> Bob
>
> On Monday, November 10, 2014 12:55 PM, Paul Baumann via 
> GemStone-Smalltalk <gemstone-smalltalk at lists.gemtalksystems.com 
> <mailto:gemstone-smalltalk at lists.gemtalksystems.com>> wrote:
>
> Re-send to list...
>
> *From:*Paul Baumann
> *Sent:* Monday, November 10, 2014 10:47
> ...
> *Subject:* RE: [GemStone-Smalltalk] Transcient instance variable
>
> Hi Bob,
>
> "System rcValueCache" is flushed  with a view/transaction change 
> (commitTransaction, abortTransaction, beginTransaction, 
> continueTransaction). Here is an example that shows view-transient 
> behavior:
>
> | anObject get0 get1 |
>
> System beginTransaction.
>
> anObject := Object new.
>
> System rcValueCacheAt: #plbTest put: #remembered for: anObject.
>
> get0 := System rcValueCacheAt: #plbTest for: anObject otherwise: nil.
>
> System commitTransaction.
>
> get1 := System rcValueCacheAt: #plbTest for: anObject otherwise: nil.
>
> Array with: get0 with: get1
>
> anArray( #'remembered', nil)
>
> Your domain object can use itself to retrieve by-reference attributes. 
> A view-transient attribute would be like this:
>
> viewTransient_plbTest
>
>                 ^System rcValueCacheAt: #plbTest for: self otherwise: nil
>
> viewTransient_plbTest: anObject
>
>                 System rcValueCacheAt: #plbTest put: anObject for: self
>
> A session-transient attribute would be like this:
>
> sessionTransient_plbTest
>
>                 |dict |
>
>                 ^(dict := SessionTemps current at: #plbTest otherwise: 
> nil) notNil
>
>                                 ifTrue: [dict at: self otherwise: nil].
>
> sessionTransient_plbTest: anObject
>
>                 (SessionTemps current at: #plbTest ifAbsentPut: 
> [IdentityDictionary new])
>
>                                 at: self put: anObject.
>
> A wrapper object held in an object attribute can be used for better 
> performance when needed. Your domain object would have an attribute 
> that holds information that can find cached data quicker. If the 
> attribute is nil then the no lookup is necessary (saving a search). If 
> the attribute is not nil then it can be something like a reserved 
> index position within a known location (not strongly referenced) that 
> would contain the data. Years ago I had prototyped a cache framework 
> that was able to use a special wrapper for weak references to related 
> objects. It can be done--if you really need that level of performance.
>
> Paul Baumann
>
> *From:*GemStone-Smalltalk 
> [mailto:gemstone-smalltalk-bounces at lists.gemtalksystems.com] *On 
> Behalf Of *via GemStone-Smalltalk
> *Sent:* Monday, November 10, 2014 08:25
> *To:* gemstone-smalltalk at lists.gemtalksystems.com 
> <mailto:gemstone-smalltalk at lists.gemtalksystems.com>
> *Subject:* [GemStone-Smalltalk] Transcient instance variable
>
> I'm considering some refactoring that would benefit from having access 
> to transcient instance variables.
>
> Something like SessionTemps, but stored on an instance variable and 
> cleared on each abort or commit.
>
> It would be used to store pending updates. We do that now with a 
> wrapper object, which works fine,
>
> but the code would be cleaner if the domain object wrapped the pending 
> updates instead.
>
> Anything like that available?
>
> Thanks for any suggestions,
>
> Bob Nemec
>
> HTS
>
> ------------------------------------------------------------------------
>
> This message may contain confidential information and is intended for 
> specific recipients unless explicitly noted otherwise. If you have 
> reason to believe you are not an intended recipient of this message, 
> please delete it and notify the sender. This message may not represent 
> the opinion of Intercontinental Exchange, Inc. (ICE), its subsidiaries 
> or affiliates, and does not constitute a contract or guarantee. 
> Unencrypted electronic mail is not secure and the recipient of this 
> message is expected to provide safeguards from viruses and pursue 
> alternate means of communication where privacy or a binding message is 
> desired.
>
>
> _______________________________________________
> GemStone-Smalltalk mailing list
> GemStone-Smalltalk at lists.gemtalksystems.com 
> <mailto:GemStone-Smalltalk at lists.gemtalksystems.com>
> http://lists.gemtalksystems.com/mailman/listinfo/gemstone-smalltalk
>
> ------------------------------------------------------------------------
>
> This message may contain confidential information and is intended for 
> specific recipients unless explicitly noted otherwise. If you have 
> reason to believe you are not an intended recipient of this message, 
> please delete it and notify the sender. This message may not represent 
> the opinion of Intercontinental Exchange, Inc. (ICE), its subsidiaries 
> or affiliates, and does not constitute a contract or guarantee. 
> Unencrypted electronic mail is not secure and the recipient of this 
> message is expected to provide safeguards from viruses and pursue 
> alternate means of communication where privacy or a binding message is 
> desired.
>
> _______________________________________________
> GemStone-Smalltalk mailing list
> GemStone-Smalltalk at lists.gemtalksystems.com 
> <mailto:GemStone-Smalltalk at lists.gemtalksystems.com>
> http://lists.gemtalksystems.com/mailman/listinfo/gemstone-smalltalk
>
>
> ------------------------------------------------------------------------
> This message may contain confidential information and is intended for 
> specific recipients unless explicitly noted otherwise. If you have 
> reason to believe you are not an intended recipient of this message, 
> please delete it and notify the sender. This message may not represent 
> the opinion of Intercontinental Exchange, Inc. (ICE), its subsidiaries 
> or affiliates, and does not constitute a contract or guarantee. 
> Unencrypted electronic mail is not secure and the recipient of this 
> message is expected to provide safeguards from viruses and pursue 
> alternate means of communication where privacy or a binding message is 
> desired.
>
>
> _______________________________________________
> GemStone-Smalltalk mailing list
> GemStone-Smalltalk at lists.gemtalksystems.com
> http://lists.gemtalksystems.com/mailman/listinfo/gemstone-smalltalk

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.gemtalksystems.com/mailman/private/gemstone-smalltalk/attachments/20141111/94c5bf1a/attachment-0001.html>


More information about the GemStone-Smalltalk mailing list