On 9 November 2010 05:59, Levente Uzonyi <[email protected]> wrote: > On Tue, 9 Nov 2010, Igor Stasenko wrote: > > snip > >> Suppose you have a domain object which provides following ways to >> access the session: >> >> session: forkedSession >> Processor activeProcess environmentAt: #session put: forkedSession >> >> session >> ^ Processor activeProcess environmentAt: #session >> >> >> now, here what i'd like to write: >> >> | session | >> >> session := MySession new . >> session initialize blabla. >> >> "good fork" >> good := [ >> self session: session. >> [ self process stuff ] ensure: [ session close ] >> ] newProcess. >> >> good resume. >> 1 minute asDelay wait. >> good terminate. >> self assert: (session isClosed). >> >> In the above case, everything is ok: session object is passed in 'session' >> temp >> and visible inside ensure block directly, so, no matter what may >> happen (process termination), >> it is guaranteed that session will be closed at the end. >> >> "bad fork" >> >> session := MySession new . >> session initialize blabla. >> >> bad := [ >> self session: session. >> [ self process stuff ] ensure: [ self session close ] >> ] newProcess. >> >> bad resume. >> 1 minute asDelay wait. >> bad terminate. >> self assert: (session isClosed). >> >> >> In this case, a session is accessed indirectly, through process specific >> state. >> And test might fail or not, depending if process was already >> terminated before sending #terminate, >> or its still running. >> >> The 'bad fork' illustrates that one should not attempt to access a >> process specific state in ensure blocks, >> because during process termination, stack unwinding is performed by >> other process, which could have different session object, >> or don't have it at all. >> >> This is simple, of course, to implement session finalization without >> using process spefic state. But now consider that session has not only >> #close method, but allows doing something more userful, like: >> >> self session backupStuff. >> [ .. do something.. ] ensure: [ self session restoreStuff ]. >> >> And again, same problem: unless you have a direct reference to session >> object, you can't do it. >> Not with using process-specific state, because it is flawed. >> >> In other words, anything which may want to access to a >> process-specific state, like: >> >> [ ... ... ] ensure: [ (Processor activeProcess environmentAt: #foo) >> doSomething ] >> >> have no guarantees to work correctly in all cases. >> >> This defeats a purpose of process-specific state, because you can't >> rely on it for building a reliable stuff. > > Not really. You can store the sessions in a session store which is > responsible for retrieving the session: > > [ > sessionStore useSession: sessionKey during: [ :session | > Processor activeProcess environmentAt: #session put: session. > self doSomething. > Processor activeProcess environmentAt: #session put: nil ] ] > fork. > > SessionStore >> useSession: sessionKey during: aBlock > > | session | > [ > session := self sessionFor: sessionKey. > aBlock value: session ] > ensure: [ > session ifNotNil: [ > self releaseSession: session ] ] > > In #doSomething you can access the session via the process. We're using this > pattern in PostgresV3's connection pool. It works pretty well. >
No, you can't. I feel sorry for you :) A #useSession:during: using ensure, and of course it will work correctly, because you not accessing session via process-specific storage. This is illustrated by my "good fork" example. now replace #doSomething with this: [ 1 year asDelay wait ] ensure: [ self assert: (Processor activeProcess environmentAt: #session) notNil ] and then terminate a process which running your fork. In attachment you'll find a test, which shows the problem (i using tests from Pharo image). > > Levente > > > snip > > -- Best regards, Igor Stasenko AKA sig.
ProcessSpecificTest-testLocalVariableInEnsureBlock.st
Description: Binary data
