Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WAFlowFunctionalTest fails on GemStone #1198

Closed
dassi opened this issue May 21, 2020 · 19 comments
Closed

WAFlowFunctionalTest fails on GemStone #1198

dassi opened this issue May 21, 2020 · 19 comments

Comments

@dassi
Copy link

dassi commented May 21, 2020

Bug summary

WAFlowFunctionalTest fails: Exception WARequestContextNotFound after seaside's call/answer

Steps

  1. Use GsDevKit, install GemStone 3.4.5 (probably not specific to that version, also failed with GemStone 3.4.3).
  2. Install Seaside with the "Tests" group, which includes the functional tests.
  3. Browse to your domain http://localhost/tests/functional/WAFlowFunctionalTest
  4. Both subtests fail with a WARequestContextNotFound

That simply means, that seaside's very basic call:/answer is not working.

My observations

  • Bug DOES NOT show up using call:onAnswer: instead of call:.
  • Bug is NOT there up to Seaside v3.2.5. But is there starting from Seaside v3.3.0. Grease has done a jump there, changing the platform specific implementation of WADynamicVariable (which WACurrentRequestContext is a subclass of). On GemStone this is now a subclass of GemStone's own DynamicVariable class, which in turn uses Processor activeProcess environment at: to get the value of the dynamic variable. I managed to figure out, that the "Processor activeProcess" changes after call:/answer, which could be OK but the process' environment dictionary is blank and the current request context is gone.
  • Seaside's error handling will in turn fail itself because it also relies on calling current requestContext itself. Only a simple text based stack is placed on GemStone's ObjectLog. And the browser just shows a simple "Internal Error:" text. Not easy to debug.
@dassi
Copy link
Author

dassi commented May 21, 2020

@jbrichau suggested:

In the meantime, you might want to change WADynamicVariable to be a subclass of GRNotificationBasedDynamicVariable instead of GRDynamicVariable and see if that fixes it?

Yeeeaahhh! That fixes it!

@dalehenrich
Copy link
Member

@dassi Glad that works for you.

Seaside's error handling will in turn fail itself because it also relies on calling current requestContext itself. Only a simple text based stack is placed on GemStone's ObjectLog. And the browser just shows a simple "Internal Error:" text. Not easy to debug.

@dassi I noticed this as well, but when the continuation mechanism fails, I'm not sure there is much to do...

@dalehenrich
Copy link
Member

@jbrichau,

From this stack:

1 GRGemStonePlatform >> logError:title:shouldCommit: @3 line 4  [GsNMethod 144132865]
2 GRGemStonePlatform >> logError:title: @2 line 3  [GsNMethod 144184321]
3 WAGemStoneProductionErrorHandler (WAErrorHandler) >> saveExceptionContinuation: @9 line 6  [GsNMethod 256494593]
4 WAGemStoneProductionErrorHandler >> handleDefault: @2 line 3  [GsNMethod 258494721]
5 WAGemStoneProductionErrorHandler (WAErrorHandler) >> handleError: @2 line 2  [GsNMethod 227332353]
6 WAGemStoneProductionErrorHandler (WAErrorHandler) >> handleGemStoneException: @5 line 4  [GsNMethod 256494337]
7 WAGemStoneProductionErrorHandler (WAHtmlHaltAndErrorHandler) >> handleException: @2 line 2  [GsNMethod 258638593]
8 [] in WAExceptionHandler >> handleExceptionsDuring: @11 line 5  [GsNMethod 244087553]
9 ExecBlock0 (ExecBlock) >> on:do: @3 line 44  [GsNMethod 4842753]
10 [] in WAExceptionHandler >> handleExceptionsDuring: @7 line 8  [GsNMethod 236780545]
11 [] in ExecBlock >> on:do: @16 line 53  [GsNMethod 7582977]
12 WARequestContextNotFound (AbstractException) >> _executeOuterHandler: @9 line 10  [GsNMethod 5939713]
13 WARequestContextNotFound (AbstractException) >> _pass:with: @5 line 13  [GsNMethod 5940993]
14 WARequestContextNotFound (AbstractException) >> pass @2 line 14  [GsNMethod 5939969]
15 [] in WAHandleAbortWouldLoseDataToolFilter >> handleFiltered: @22 line 12  [GsNMethod 261445121]
16 WARequestContextNotFound (AbstractException) >> _executeHandler: @8 line 11  [GsNMethod 5946369]
17 WARequestContextNotFound (AbstractException) >> _signalWith: @1 line 1  [GsNMethod 5946881]
18 WARequestContextNotFound class (AbstractException class) >> signal @3 line 5  [GsNMethod 5926913]
19 WACurrentRequestContext class >> defaultValue @2 line 2  [GsNMethod 263758081]
20 [] in GRDynamicVariable class >> value @9 line 4  [GsNMethod 145268225]
21 Dictionary >> at:ifAbsent: @8 line 10  [GsNMethod 13376513]
22 WACurrentRequestContext class (GRDynamicVariable class) >> value @5 line 4  [GsNMethod 144199425]
23 WACallbackProcessingActionContinuation (WAObject) >> requestContext @2 line 4  [GsNMethod 226200577]
24 WACallbackProcessingActionContinuation (WAObject) >> session @2 line 4  [GsNMethod 226200321]
25 WACallbackProcessingActionContinuation (WARenderLoopContinuation) >> presenter @2 line 4  [GsNMethod 230659585]
26 WACallbackProcessingActionContinuation (WAActionPhaseContinuation) >> startTasks @4 line 3  [GsNMethod 230781953]
27 WACallbackProcessingActionContinuation (WAActionPhaseContinuation) >> performAction @4 line 3  [GsNMethod 230780929]
28 [] in WACallbackProcessingActionContinuation >> performAction @7 line 3  [GsNMethod 241345025]
29 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
30 WACallbackProcessingActionContinuation >> performAction @3 line 3  [GsNMethod 230842625]
31 WACallbackProcessingActionContinuation (WAActionPhaseContinuation) >> handleFiltered: @2 line 2  [GsNMethod 230782977]
32 [] in WARequestHandler >> handle: @8 line 4  [GsNMethod 239279361]
33 [] in GRDynamicVariable class >> use:during: @15 line 12  [GsNMethod 145268737]
34 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
35 WACurrentRequestContext class (GRDynamicVariable class) >> use:during: @10 line 13  [GsNMethod 144200193]
36 [] in WARequestContext >> push:during: @8 line 5  [GsNMethod 236848897]
37 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
38 WAGemStoneRequestContext (WARequestContext) >> push:during: @4 line 6  [GsNMethod 225268737]
39 WACallbackProcessingActionContinuation (WARequestHandler) >> handle: @3 line 4  [GsNMethod 227822849]
40 [] in WASessionContinuation >> handle: @9 line 5  [GsNMethod 237088001]
41 ExecBlock0 (ExecBlock) >> on:do: @3 line 44  [GsNMethod 4842753]
42 WACallbackProcessingActionContinuation (WASessionContinuation) >> withUnregisteredHandlerDo: @3 line 3  [GsNMethod 226502145]
43 WACallbackProcessingActionContinuation (WASessionContinuation) >> handle: @5 line 5  [GsNMethod 226502657]
44 WAExpirySession (WASession) >> handleFiltered: @21 line 20  [GsNMethod 226070017]
45 WATimingToolFilter (WARequestFilter) >> handleFiltered: @3 line 4  [GsNMethod 227867393]
46 [] in WATimingToolFilter >> handleFiltered: @9 line 3  [GsNMethod 262485505]
47 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
48 WATimingToolFilter >> handleFiltered: @5 line 4  [GsNMethod 259542529]
49 WADeprecatedToolFilter (WARequestFilter) >> handleFiltered: @3 line 4  [GsNMethod 227867393]
50 [] in WADeprecatedToolFilter >> handleFiltered: @10 line 2  [GsNMethod 262573825]
51 ExecBlock0 (ExecBlock) >> on:do: @3 line 44  [GsNMethod 4842753]
52 WADeprecatedToolFilter >> handleFiltered: @6 line 3  [GsNMethod 258619649]
53 WAHandleAbortWouldLoseDataToolFilter (WARequestFilter) >> handleFiltered: @3 line 4  [GsNMethod 227867393]
54 [] in WAHandleAbortWouldLoseDataToolFilter >> handleFiltered: @7 line 2  [GsNMethod 261445377]WAPartialContinuationTest
55 ExecBlock0 (ExecBlock) >> on:do: @3 line 44  [GsNMethod 4842753]
56 WAHandleAbortWouldLoseDataToolFilter >> handleFiltered: @3 line 3  [GsNMethod 258468097]
57 WAGsMutualExclusionFilter (WARequestFilter) >> handleFiltered: @3 line 4  [GsNMethod 227867393]
58 WAGsMutualExclusionFilter >> handleFiltered: @11 line 11  [GsNMethod 230256897]
59 [] in WARequestHandler >> handle: @8 line 4  [GsNMethod 239279361]
60 [] in GRDynamicVariable class >> use:during: @15 line 12  [GsNMethod 145268737]
61 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
62 WACurrentRequestContext class (GRDynamicVariable class) >> use:during: @10 line 13  [GsNMethod 144200193]
63 [] in WARequestContext >> push:during: @8 line 5  [GsNMethod 236848897]
64 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
65 WAGemStoneRequestContext (WARequestContext) >> push:during: @4 line 6  [GsNMethod 225268737]
66 WAExpirySession (WARequestHandler) >> handle: @3 line 4  [GsNMethod 227822849]
67 WAApplication (WARegistry) >> dispatch:to:key: @4 line 6  [GsNMethod 227063553]
68 WAApplication (WARegistry) >> handleKeyed:with:context: @2 line 5  [GsNMethod 227065345]
69 WAApplication (WARegistry) >> handleFiltered: @16 line 13  [GsNMethod 227063809]
70 WAApplication >> handleFiltered: @10 line 8  [GsNMethod 226452481]
71 WAExceptionFilter (WARequestFilter) >> handleFiltered: @3 line 4  [GsNMethod 227867393]
72 [] in WAExceptionFilter >> handleFiltered: @14 line 7  [GsNMethod 244057345]
73 [] in GRDynamicVariable class >> use:during: @15 line 12  [GsNMethod 145268737]
74 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
75 WACurrentExceptionHandler class (GRDynamicVariable class) >> use:during: @10 line 13  [GsNMethod 144200193]
76 [] in WAExceptionFilter >> handleFiltered: @10 line 6  [GsNMethod 238204161]
77 ExecBlock0 (ExecBlock) >> onException:do: @2 line 66  [GsNMethod 4843265]
78 ExecBlock0 (ExecBlock) >> on:do: @5 line 49  [GsNMethod 4842753]
79 WAGemStoneProductionErrorHandler (WAExceptionHandler) >> handleExceptionsDuring: @3 line 3  [GsNMethod 226212353]
80 WAExceptionFilter >> handleFiltered: @6 line 4  [GsNMethod 226872833]
81 [] in WARequestHandler >> handle: @8 line 4  [GsNMethod 239279361]
82 [] in GRDynamicVariable class >> use:during: @15 line 12  [GsNMethod 145268737]
83 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
84 WACurrentRequestContext class (GRDynamicVariable class) >> use:during: @10 line 13  [GsNMethod 144200193]
85 [] in WARequestContext >> push:during: @8 line 5  [GsNMethod 236848897]
86 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
87 WAGemStoneRequestContext (WARequestContext) >> push:during: @4 line 6  [GsNMethod 225268737]
88 WAApplication (WARequestHandler) >> handle: @3 line 4  [GsNMethod 227822849]
89 WADispatcher >> handleFiltered:named: @4 line 5  [GsNMethod 227852801]
90 WADispatcher >> handleFiltered: @9 line 6  [GsNMethod 227855105]
91 [] in WARequestHandler >> handle: @8 line 4  [GsNMethod 239279361]
92 [] in GRDynamicVariable class >> use:during: @15 line 12  [GsNMethod 145268737]
93 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
94 WACurrentRequestContext class (GRDynamicVariable class) >> use:during: @10 line 13  [GsNMethod 144200193]
95 [] in WARequestContext >> push:during: @8 line 5  [GsNMethod 236848897]
96 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
97 WAGemStoneRequestContext (WARequestContext) >> push:during: @4 line 6  [GsNMethod 225268737]
98 WADispatcher (WARequestHandler) >> handle: @3 line 4  [GsNMethod 227822849]
99 WADispatcher >> handleFiltered:named: @4 line 5  [GsNMethod 227852801]
100 WADispatcher >> handleFiltered: @9 line 6  [GsNMethod 227855105]
101 [] in WARequestHandler >> handle: @8 line 4  [GsNMethod 239279361]
102 [] in GRDynamicVariable class >> use:during: @15 line 12  [GsNMethod 145268737]
103 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
104 WACurrentRequestContext class (GRDynamicVariable class) >> use:during: @10 line 13  [GsNMethod 144200193]
105 [] in WARequestContext >> push:during: @8 line 5  [GsNMethod 236848897]
106 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
107 WAGemStoneRequestContext (WARequestContext) >> push:during: @4 line 6  [GsNMethod 225268737]
108 WADispatcher (WARequestHandler) >> handle: @3 line 4  [GsNMethod 227822849]
109 [] in WAServerAdaptor >> handleRequest: @8 line 4  [GsNMethod 239104001]
110 ExecBlock0 (ExecBlock) >> on:do: @3 line 44  [GsNMethod 4842753]
111 WAZincNewGemServerAdaptor (WAServerAdaptor) >> handleRequest: @3 line 5  [GsNMethod 228677121]
112 WAZincNewGemServerAdaptor (WAServerAdaptor) >> handle: @2 line 4  [GsNMethod 228677633]
113 [] in WAServerAdaptor >> process: @9 line 6  [GsNMethod 239099649]
114 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
115 WAZincNewGemServerAdaptor (WAServerAdaptor) >> process: @5 line 9  [GsNMethod 228673281]
116 [] in WAGsZincAdaptor >> process: @8 line 6  [GsNMethod 262340865]
117 [] in GRGemStonePlatform >> seasideProcessRequestWithRetry:resultBlock: @45 line 12  [GsNMethod 236003329]
118 ExecBlock0 (ExecBlock) >> on:do: @3 line 44  [GsNMethod 4842753]
119 [] in GRGemStonePlatform >> seasideProcessRequestWithRetry:resultBlock: @17 line 13  [GsNMethod 225439745]
120 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
121 TransientRecursionLock >> critical: @12 line 12  [GsNMethod 37998593]
122 GRGemStonePlatform >> seasideProcessRequestWithRetry:resultBlock: @4 line 6  [GsNMethod 222547201]
123 [] in GRGemStonePlatform >> seasideProcessRequest:adaptor:resultBlock: @18 line 6  [GsNMethod 237026049]
124 Array (Collection) >> do: @6 line 10  [GsNMethod 1910273]
125 [] in GRGemStonePlatform >> seasideProcessRequest:adaptor:resultBlock: @8 line 5  [GsNMethod 225435905]
126 ExecBlock0 (ExecBlock) >> on:do: @3 line 44  [GsNMethod 4842753]
127 GRGemStonePlatform >> seasideProcessRequest:adaptor:resultBlock: @3 line 12  [GsNMethod 222544385]
128 WAZincNewGemServerAdaptor (WAGsZincAdaptor) >> process: @4 line 4  [GsNMethod 259367169]
129 ZnSeasideServerAdaptorDelegate >> handleRequest: @3 line 4  [GsNMethod 258434305]
130 ZnSeasideServerAdaptorDelegate >> handleRequest:gemServer: @2 line 4  [GsNMethod 258434049]
131 [] in ZnGemServerManagingMultiThreadedServer >> authenticateAndDelegateRequest: @13 line 12  [GsNMethod 262549505]
132 ZnGemServerManagingMultiThreadedServer (ZnSingleThreadedServer) >> authenticateRequest:do: @5 line 6  [GsNMethod 172439041]
133 ZnGemServerManagingMultiThreadedServer >> authenticateAndDelegateRequest: @3 line 8  [GsNMethod 258589441]
134 [] in ZnGemServerManagingMultiThreadedServer >> handleRequestProtected: @7 line 6  [GsNMethod 262546433]
135 ExecBlock0 (ExecBlock) >> on:do: @3 line 44  [GsNMethod 4842753]
136 [] in GemServer >> gemServer:exceptionSet:beforeUnwind:ensure: @7 line 4  [GsNMethod 261719297]
137 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
138 ZnSeasideNewGemServer (GemServer) >> gemServer:exceptionSet:beforeUnwind:ensure: @3 line 22  [GsNMethod 258811649]
139 ZnSeasideNewGemServer (GemServer) >> gemServer:exceptionSet:beforeUnwind: @2 line 3  [GsNMethod 258813953]
140 ZnGemServerManagingMultiThreadedServer >> serve:onError: @3 line 5  [GsNMethod 258589697]
141 ZnGemServerManagingMultiThreadedServer >> handleRequestProtected: @3 line 6  [GsNMethod 258587649]
142 ZnGemServerManagingMultiThreadedServer (ZnSingleThreadedServer) >> handleRequest: @6 line 9  [GsNMethod 172443393]
143 [] in ZnGemServerManagingMultiThreadedServer >> executeOneRequestResponseOn: @10 line 20  [GsNMethod 262544129]
144 ExecBlock0 (ExecBlock) >> on:do: @3 line 44  [GsNMethod 4842753]
145 [] in GemServer >> gemServer:exceptionSet:beforeUnwind:ensure: @7 line 4  [GsNMethod 261719297]
146 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
147 ZnSeasideNewGemServer (GemServer) >> gemServer:exceptionSet:beforeUnwind:ensure: @3 line 22  [GsNMethod 258811649]
148 ZnSeasideNewGemServer (GemServer) >> gemServer:beforeUnwind:ensure: @3 line 3  [GsNMethod 258806017]
149 ZnSeasideNewGemServer (GemServer) >> gemServer:ensure: @2 line 3  [GsNMethod 258813441]
150 ZnGemServerManagingMultiThreadedServer >> serve:ensure: @3 line 4  [GsNMethod 258589953]
151 ZnGemServerManagingMultiThreadedServer >> executeOneRequestResponseOn: @3 line 10  [GsNMethod 258586113]
152 [] in ZnGemServerManagingMultiThreadedServer >> serveConnectionsOn: @28 line 16  [GsNMethod 263438593]
153 [] in DynamicVariable class >> value:during: @16 line 9  [GsNMethod 89104129]
154 ExecBlock0 (ExecBlock) >> ensure: @2 line 12  [GsNMethod 4845825]
155 ZnCurrentServer class (DynamicVariable class) >> value:during: @7 line 10  [GsNMethod 71356673]
156 [] in ZnGemServerManagingMultiThreadedServer >> serveConnectionsOn: @24 line 15  [GsNMethod 262542081]
157 ExecBlock >> valueWithArguments: @1 line 1  [GsNMethod 4849921]
158 GsProcess >> _start @8 line 16  [GsNMethod 4953345]
159 <Reenter marker>

it seems that this issue is coming up because the environment dictionary (where the dynamic variable is stored in GsProcess) is not being handled correctly in the presence of continuations ... I've talked to @AllenOtis and internally we do not preserve the environment dictionary when we restore a full continuation, but we DO preserve the environment dictionary when we restore a partial continuation. To be clear, the environment dictionary that was associated with the original process that the partial continuation was associated with is NOT preserved. We DO preserve the environment dictionary of the process into which the partiali continuation is restored ...

Looking at this stack I see that Dynamic Variables are defined (GrDynamicVairable class>>use:during:) in the frames: 35*, 62*, 75, 84*, 94*, 104* ... the *'d frames are where WACurrentRequestContext is being called ... all but one (75) have the same key so the WACurrentRequestContext from frame 35 should win ... The WARequestContextNotFound is signaled because no entry exists in the environment dictionary of the current GsProcess.

Thinking that we should be able to reproduce this bug in a simple test case based on the WAPartialContinuationTest, I've fiddled around a bit and finally think that I may have reproduced the bug with a variant of WAPartialContinuationTest>>testReentrant:

testReentrant
  | kk x |
  self
    assert:
      (self
        mark: [
          2
            *
              (self
                callcc: [ :cc |
                  kk := cc.
                  2 ]) ])
        = 4.
  WADynamicVariable
    use: 6
    during: [
      self assert: (self mark: [ kk value: (x := WADynamicVariable value) ]) = 12.
      self
        assert: (self mark: [ kk value: (x := WADynamicVariable value) ]) = 12.
      self
        assert: (self mark: [ kk value: (x := WADynamicVariable value) ]) = 12 ]

When I run this test I get a failure in the second invocation of the continuation and the value returned by WADynamicVariable is nil, which (i think) corresponds to the failure mode we are seeing in the stack ... I am not able to identify the continuation boundaries in the stack, nor am I able to determine if there could be multiple activations of the same continuation in the WAFlowFunctionalTest. I see that startTasks is called, so I assume that there is potential for that to go on ...

Anyway we won't be able to do more work on this bug until next week.

@jbrichau
Copy link
Member

jbrichau commented May 22, 2020

Much appreciated @dalehenrich!

If I understand correct, the GsProcess>>installPartialContinuation:... method (which is a primitive) creates a new GsProcess instance, which does not have the environment from the current GsProcess instance. I assume this means it would need to be changed in the vm and we need to revert to GRNotificationBasedDynamicVariable otherwise.

If I change your test (just for my understanding purposes), to show that the process environment is thrown away. From within the test, I can restore the environment to make the test work but I could not do that in the implementation of WAPartialEvaluation>>value:.

  | kk x |
  self
    assert:
      (self
        mark: [ 
          2
            *
              (self
                callcc: [ :cc | 
                  kk := cc.
                  2 ]) ])
        = 4.
  WADynamicVariable
    use: 6
    during: [ 
      | env p |
      env := Processor activeProcess environment.
      p := Processor activeProcess.
      self
        assert: (self mark: [ kk value: (x := WADynamicVariable value) ]) = 12.
      self deny: Processor activeProcess == p.
      Processor activeProcess environment: env.
      self
        assert: (self mark: [ kk value: (x := WADynamicVariable value) ]) = 12.
      Processor activeProcess environment: env.
      self
        assert: (self mark: [ kk value: (x := WADynamicVariable value) ]) = 12 ]

@dalehenrich
Copy link
Member

@jbrichau, it looks like it might be possible to arrange to preserve the environment dictionary across the GsProcess>>installPartialContinuation:... by monkeying with WAPartialContinuation>>value:. There's a setter for the environment dictionary in GsProcess, so that might be a straightforward patch ... I don't have the cycles today to check that out, but it might be a better patch than reverting the implementation of WADynamicVariable.

@jbrichau
Copy link
Member

@dalehenrich I tried that but my monkeying was not working. but will give it a second try once I get back to my console today ;)

@jbrichau
Copy link
Member

jbrichau commented May 22, 2020

I tried this by setting the environment of the partial before passing it to the GsProcess>>installPartialContinuation but the resulting GsProcess instance still has an empty environment.

...
 partial environment: Processor activeProcess environment.
  ^ GsProcess
    installPartialContinuation: partial
    atLevel: frameIndex
    value: anObject

@jbrichau
Copy link
Member

Some more monkeying today brought me to the following hack in Seaside to make the combination of DynamicVariable and partial continuations work in Gemstone. This fixes the WAFlowFunctionalTest example but might not be complete (I'll get back to it later). The following two methods need changing:

WAComponent>>wait: aBlock
  "Evaluate aBlock and pass in a continuation that can be evaluated to answer to the place where this very method was called."

  | dict |
  dict := GRPlatform current seasideSuspendFlowDo: [ :cc | aBlock value: cc ].
  Processor activeProcess environment: (dict at: 'env').
  ^ dict at: 'value'
WAPartialContinuation>>value: anObject
  | marker frameIndex |
  marker := self markerBlock value.
  marker isNil
    ifTrue: [ 
      marker := (GsProcess _frameContentsAt: 2) at: 1.
      frameIndex := 2 ]
    ifFalse: [ frameIndex := self class findFrameIndexFor: marker ].
  ^ GsProcess
    installPartialContinuation: partial
    atLevel: frameIndex
    value:
      (Dictionary new
        at: 'env' put: Processor activeProcess environment;
        at: 'value' put: anObject;
        yourself)

The essence is to 'pass through' the environment of the process in which the partial continuation is restored such that its environment is still the same after the partial continuation is restored.

@dalehenrich I need to verify if this is a complete and sound workaround. The other question would be: would it be feasible to have the environment copying made a possibility of the GsProcess>>installPartialContinuation:... primitive in later Gs versions?

@jbrichau
Copy link
Member

An implementation of the same workaround that fits in Gemstone-only packages is made in #1201

I also have the Parasol automation for these tests ready in #1199 but some other failures appear in the Gemstone tests because of that. It's probably related to the presence of Parasol so I will check later this week.

@dalehenrich in case you are able to cast an eye. Would be great!

@dalehenrich
Copy link
Member

@jbrichau if I'm reading the patch code correctly we are in a position where the environment from the partial continuation is the environment that needs to be restored? Is that right ... that was a missing piece from our partial continuation implementation from the beginning ...

I'm busy today (yesterday was a holiday), but I will take #1199 for a spin tomorrow ...

@jbrichau
Copy link
Member

Hey @dalehenrich, as I am trying to finalize PR #1201 by fixing the failing tests, I am left wondering what WAPartialContinuationAlternatMarker and its corresponding test class are about.

See https://travis-ci.org/github/SeasideSt/Seaside/builds/692678006 for the last build. The failing tests are 'normal'. The context where the partial continuation resumes does not deal with the monkey patch of passing the environment in a dictionary. I'm still fiddling.

@dalehenrich
Copy link
Member

Spelunking in the git history:

If I recall that far back (sketchy at best) I copied the pharo continuation tests for GemStone and got them to work ... and then relied on keeping the tests passin from that point on ... If this wasn't a pharo test, then I must have created it and misspelled Alternate. I don't know when we started supporting partial continuations (and I'm not going to try to spelunk through Monticello history), ut I wouldn't be surprised if was experimenting with different stack markers in an attempt to reproduce bugs we were seeing in running Seaside and Seaside tests ... if I had passing tests I would have left them in even if they didn't reproduce the error ...

If it doesn't represent a current use case, then I'm not sure it is worth keeping ...

@dalehenrich
Copy link
Member

Whoa, I realized that I would have the comments in the mcz package:
image
Started in September 2009, and clearly working getting partial continuations ported to GemStone... as I suspected I was trying to reproduce bugs ... and by November of 2009, it seems that I was finished ... probably haven't changed much since then ... so if there are no Pharo tests form that time period that are testing AlternateMarkers then I would say it can be dropped ... we don't use continuations for anything but Seaside ...

@jbrichau
Copy link
Member

I finalized the implementation of a workaround for this issue in #1201

@dassi Do you see an opportunity to test the fixes done in that branch on your application before I add them to the master? Thanks again for reporting and sorry for the hassle. It took me a little longer to fix the issue because I also have taken the time to add the functional test automation to the testsuite. This will at least help to prevent this kind of mistakes in the future. It will also help if I actually use the latest version of Seaside in production in the future as well ;-)

@dalehenrich Any chance of being able to pass the environment to the primitive in future GemStone versions? Or if you see a better workaround, I am all ears. BTW, notice that builds for GemStone 3.5.0 have started failing on loading FileTree... (see https://travis-ci.org/github/SeasideSt/Seaside/jobs/702633712 ) This is strange because I do not see that anywhere else where I am loading in GemStone 3.5.0. And it should not have anything to do with changes for this issue. I have a working load with the parasol tests added in this build of a month ago: https://travis-ci.org/github/SeasideSt/Seaside/jobs/690603830

@dalehenrich
Copy link
Member

I'm going to be push my Rowan work on the stack for awhile while I spend some quality time with GLASS, we've got the SeasideSt/Grease#105, Metacello/metacello#514, and https://travis-ci.org/github/GsDevKit/zinc/builds/702795787 issues outstanding ...

Interestingly enough I just did a GsDevKit_home build with the fresh clones of all of the projects including FileTree and Grease without any failures, so this is a real odd one .... well, I'll be spending full time on these guys until I've figured them out ... so we will see what I find out ...

@dalehenrich
Copy link
Member

I think that there is a chance, but it won't make it into 3.5.x and it may or may not make it into 3.6.x --- which is why I've been working on Rowan pretty exclusively .... we've got a customer that would like some 3.6.0-only features this fall and that is putting a mighty squeeze on me:)

@jbrichau
Copy link
Member

I understand that this is not going to be implemented very soon, but I wanted to understand if it would be feasible to do so in the future. I will then track the permanent solution that remove the workaround code in a future release for a future version of GemStone ;)

jbrichau added a commit that referenced this issue Jun 30, 2020
…e GsProcess environment, breaking dynamic variables (#1201)

* Preserve GSProcess.environment across restore of partial continuation (fixes issue #1198)
* Fix for workaround in GRGemStonePlatform>>seasideSupendFlowDo: such that we only try to overwrite the environment when control is returned here as the result of restoring the partial continuation.
* Fix functional tests for running in Gemstone + add workaround fix to the partial continuation tests
* Converted use of Dictionary instance to use of a proper class (WAGemStoneProcessEnvironmentWrapper) in the implementation for the workaround for github issue 1198. Added a test for the specific case.
* do not use latestMetacello setting for gemstone builds
@jbrichau
Copy link
Member

@dassi I am closing this as I went ahead and merged this into master. A new Seaside version will be released soon, as I fix some more issues. If you find the opportunity to do some testing of the fix in your app, that would always be appreciated.

@dalehenrich
Copy link
Member

@jbrichau keep an eye out for internal bug 48863 "Restore of partial continuations does not preserve GsProcess environment, breaking dynamic variables"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants