[Glass] Class var and class inst var caches in libraries

monty via Glass glass at lists.gemtalksystems.com
Fri Oct 7 19:34:42 PDT 2016


> Sent: Friday, October 07, 2016 at 5:40 PM
> From: "Dale Henrichs via Glass" <glass at lists.gemtalksystems.com>
> To: glass at lists.gemtalksystems.com
> Subject: Re: [Glass] Class var and class inst var caches in libraries
>
> Monty,
> 
> If there is the chance for concurrent updates by different GsProcesses 
> running in the same vm, then the access should be protected by a 
> Semaphore ...

Isn't this always the case with lazily initialized SessionTemps? If a user forks off multiple processes that send the message triggering SessionTemp lazy initialization at the same time, unless SessionTemp>>#at:ifAbsentPut: is atomic or reentrant, the dictionary's internal state could be corrupted--even if the #at:ifAbsentPut: args are identical. So this could be a source of rare bugs (which is unacceptable to me), and it's not obvious how library authors can make their libraries both conflict-free and #fork-safe on GS.

I'm leaning towards using explicit initialization for all immutable values assigned to class and class isnt vars (which will persist), and then for values that mutate, to avoid locks, lazy initialization with SessionTemps but with access guarded by a global transient lock. Persisting immutable values explicitly initialized in a class #initialize method will unfortunately disallow class reinitialization with multiple Gems (would cause conflicts).

> Instances of Semaphore cannot be persisted, but you can persist a 
> reference to a TransientSemaphore instance (created during class 
> initialization). The field values in TransientSemaphore are not 
> persisted while the TransientSemaphore itself _is_ persisted ...
> 
> Dale

I already use TransientRecursionLock to lock non-persistent collections stored in class/class inst vars that are mutated after creation to make them #fork safe (Mutex is used on Pharo/Squeak to do the same).

> 
> On 10/7/16 12:12 PM, monty via Glass wrote:
> > My mail client wrongly sent this response to Dale, not to the list, so I'm forwarding it
> >
> >> Sent: Friday, October 07, 2016 at 3:05 PM
> >> From: monty <monty2 at programmer.net>
> >> To: dale.henrichs at gemtalksystems.com
> >> Subject: Re: [Glass] Class var and class inst var caches in libraries
> >>
> >> Thanks, I think this will do, but I have one more question. If a class method lazily initializes a SessionTemp to the same value (using at:ifAbsentPut: for example), but that method is executed at roughly the same time in different processes (due to fork), is there a possibility that "SessionTemps current" itself could get corrupted? For example, that it could report an inaccurate #size, or that its internal state in some other way could get corrupted due to the concurrent update?
> >>
> >>> Sent: Tuesday, October 04, 2016 at 3:21 PM
> >>> From: "Dale Henrichs via Glass" <glass at lists.gemtalksystems.com>
> >>> To: glass at lists.gemtalksystems.com
> >>> Subject: Re: [Glass] Class var and class inst var caches in libraries
> >>>
> >>> Yes, lazy initialization for shared variables in a multi-gem system is
> >>> not a good idea.
> >>>
> >>> Since it sounds like you do not need the values persisted and shared
> >>> between gems, you should be using the class SessionTemps. Here's an
> >>> example from Collection class>>randomForPicking:
> >>>
> >>> randomForPicking
> >>>     | random |
> >>>     random := SessionTemps current
> >>>       at: #'COLLECTION_RANDOM_FOR_PICKING'
> >>>       otherwise: nil.
> >>>     random == nil
> >>>       ifTrue: [ random := Random new.
> >>>         SessionTemps current at: #'COLLECTION_RANDOM_FOR_PICKING' put:
> >>> random ].
> >>>     ^ random
> >>>
> >>> SessionTemps is a subclass of SymbolDictionary and can be used for
> >>> storing session-specific globals.
> >>>
> >>> If you have the need to sharing persistent values then an explicit
> >>> initialization in the class initialization method is the right answer.
> >>> The initialize method gets run during install and at least the
> >>> initialization is safe from commit conflicts.
> >>>
> >>> Dale
> >>>
> >>>
> >>> On 10/04/2016 11:56 AM, monty via Glass wrote:
> >>>> Lots of libraries use caches stored in class vars and class isnt vars that are either explicitly or lazily initialized. But with multiple Gems accessing the same repo, this can produce write-write conflicts. In fact, simply sending #initialize to the same class from different Gems can cause them. What are the best ways to implement these caches in GS? Write-locks seem like overkill, so I'm interested in simple ways of making them non-persistent.
> >>>> _______________________________________________
> >>>> Glass mailing list
> >>>> Glass at lists.gemtalksystems.com
> >>>> http://lists.gemtalksystems.com/mailman/listinfo/glass
> >>> _______________________________________________
> >>> Glass mailing list
> >>> Glass at lists.gemtalksystems.com
> >>> http://lists.gemtalksystems.com/mailman/listinfo/glass
> >>>
> > _______________________________________________
> > Glass mailing list
> > Glass at lists.gemtalksystems.com
> > http://lists.gemtalksystems.com/mailman/listinfo/glass
> 
> _______________________________________________
> Glass mailing list
> Glass at lists.gemtalksystems.com
> http://lists.gemtalksystems.com/mailman/listinfo/glass
> 


More information about the Glass mailing list