On 9 November 2010 05:59, Levente Uzonyi <leves@elte.hu> 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.