You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Sylvain Wallez <sy...@anyware-tech.com> on 2003/03/19 18:36:33 UTC

Problem with JPetStore

Hi,

I'm playing and digging in flow-enabled petstore (BTW, so nice, I love 
it), and experienced some problems with the continutation-enabled 
prev/next navigation.

To reproduce it, go to the "dogs" area, click "next" once and then hit 
the browser's reload button. The prev and next links are now totally 
screwed.

Any ideas on what's going on ?

Moreover, AFAIU, the "productList" variable in viewCategory() is stored 
in the continuation, and so if we hit "next" and then "prev", the first 
list exists twice (in different continuations). Isn't there a potential 
memory consumption problem ? I know continuations expire, but withing 
the expiration delay, all these lists keep floating around...

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }



Re: Problem with JPetStore

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Christopher Oliver wrote:

> Sylvain Wallez wrote:
>
>> Here's my test (see below). I modified the viewCategory function in 
>> PetStore to track the value of "skipResults", and observed that when 
>> you use the browser back button and then reload the page, 
>> "skipResults" is correctly restored but not "foo.skip" which is set 
>> to the same value.
>>
>> However, I realize now that my analyzis of the result (special 
>> handing of primitive types) was wrong. Writing "skipResults = 1" in 
>> JavaScript is equivalent to writing "Integer skipResults = new 
>> Integer(1)" in Java. This means "skipResults" refers to a new object 
>> of type Integer. And the reference to this object is restored when 
>> the continuation is restored.
>>
>
> Yes, that's correct.


Cool.

> Now can you help me with this problem:
>
> http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=104818906732548&w=2 :) 


Ok, I'll give it a look over the week end (it's past 8pm european time)

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }



Re: Problem with JPetStore

Posted by Christopher Oliver <re...@verizon.net>.
Sylvain Wallez wrote:
> Christopher Oliver wrote:
> 
>> Sylvain Wallez wrote: 
> 
> 
> 
> <snip/>
> 
>>> Does JavaScript, like Java, make a difference between primitive types 
>>> (stored by value on the stack) and object types (stored by reference) 
>>> ? My understanding after some tests is that a difference is made.
>>
>>
>>
>> No, there shouldn't be any difference. If there is, it's a bug. What 
>> was your test? 
> 
> 
> 
> Here's my test (see below). I modified the viewCategory function in 
> PetStore to track the value of "skipResults", and observed that when you 
> use the browser back button and then reload the page, "skipResults" is 
> correctly restored but not "foo.skip" which is set to the same value.
> 
> However, I realize now that my analyzis of the result (special handing 
> of primitive types) was wrong. Writing "skipResults = 1" in JavaScript 
> is equivalent to writing "Integer skipResults = new Integer(1)" in Java. 
> This means "skipResults" refers to a new object of type Integer. And the 
> reference to this object is restored when the continuation is restored.
> 

Yes, that's correct. Now can you help me with this problem:

http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=104818906732548&w=2 :)

Regards,

Chris


Re: Problem with JPetStore

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Tony Collen wrote:

>On Fri, 21 Mar 2003, Sylvain Wallez wrote:
>
>  
>
>>Christopher Oliver wrote:
>>
>>    
>>
>>>Sylvain Wallez wrote:
>>>      
>>>
>><snip/>
>>
>>    
>>
>>>>Does JavaScript, like Java, make a difference between primitive types
>>>>(stored by value on the stack) and object types (stored by reference)
>>>>? My understanding after some tests is that a difference is made.
>>>>        
>>>>
>>>No, there shouldn't be any difference. If there is, it's a bug. What
>>>was your test?
>>>      
>>>
>
>>From http://www.forerunners.org/WebLibrary/jscript/ch09_03.htm :
>
> The basic rule in JavaScript is this: primitive types are manipulated by
>value, and reference types, as the name suggests, are manipulated by
>reference. Numbers and Booleans are primitive types in
>JavaScript--primitive because the consist of nothing more than a small
>fixed number of bytes, bytes that are very easily manipulated at the low
>(primitive) levels of the JavaScript interpreter. On the other hand,
>objects and arrays are reference types. These data types can contain
>arbitrary numbers of properties or elements, and so can be of arbitrary
>size, and cannot be so easily manipulated. Since object and array values
>can become quite large, it doesn't make sense to manipulate these types by
>value, which could involve the inefficient copying and comparing of large
>amounts of memory.
>
>AFAIK, that's just like Java.
>

Christopher says that Rhino makes no difference between "object" types 
and primitive types. Now if we consider primitive types as being 
represented like the immutable objectified Java primitive types 
(Integer, Boolean, etc), there's not much difference between passing an 
immutable object by reference and a real primitive type by value.

But that's nitcpicking ;-)

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }



Re: Problem with JPetStore

Posted by Tony Collen <tc...@neuagency.com>.
On Fri, 21 Mar 2003, Sylvain Wallez wrote:

> Christopher Oliver wrote:
>
> > Sylvain Wallez wrote:
>
>
> <snip/>
>
> >> Does JavaScript, like Java, make a difference between primitive types
> >> (stored by value on the stack) and object types (stored by reference)
> >> ? My understanding after some tests is that a difference is made.
> >
> >
> > No, there shouldn't be any difference. If there is, it's a bug. What
> > was your test?

>From http://www.forerunners.org/WebLibrary/jscript/ch09_03.htm :

 The basic rule in JavaScript is this: primitive types are manipulated by
value, and reference types, as the name suggests, are manipulated by
reference. Numbers and Booleans are primitive types in
JavaScript--primitive because the consist of nothing more than a small
fixed number of bytes, bytes that are very easily manipulated at the low
(primitive) levels of the JavaScript interpreter. On the other hand,
objects and arrays are reference types. These data types can contain
arbitrary numbers of properties or elements, and so can be of arbitrary
size, and cannot be so easily manipulated. Since object and array values
can become quite large, it doesn't make sense to manipulate these types by
value, which could involve the inefficient copying and comparing of large
amounts of memory.

AFAIK, that's just like Java.

Tony



Re: Problem with JPetStore

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Christopher Oliver wrote:

> Sylvain Wallez wrote: 


<snip/>

>> Does JavaScript, like Java, make a difference between primitive types 
>> (stored by value on the stack) and object types (stored by reference) 
>> ? My understanding after some tests is that a difference is made.
>
>
> No, there shouldn't be any difference. If there is, it's a bug. What 
> was your test? 


Here's my test (see below). I modified the viewCategory function in 
PetStore to track the value of "skipResults", and observed that when you 
use the browser back button and then reload the page, "skipResults" is 
correctly restored but not "foo.skip" which is set to the same value.

However, I realize now that my analyzis of the result (special handing 
of primitive types) was wrong. Writing "skipResults = 1" in JavaScript 
is equivalent to writing "Integer skipResults = new Integer(1)" in Java. 
This means "skipResults" refers to a new object of type Integer. And the 
reference to this object is restored when the continuation is restored.

function viewCategory() {
    var categoryId = cocoon.request.get("categoryId");
    var category = getPetStore().getCategory(categoryId);
    var skipResults = 0;
    var maxResults = MAX_RESULTS;
    var foo = new Object();
    foo.skip = skipResults + 0;
    while (true) {
        print("foo before = " + foo.skip);
        print("skipResults = " + skipResults);
        foo.skip = skipResults + 0;
        print("foo after = " + foo.skip);

        var productList =
            getPetStore().getProductListByCategory(categoryId,
                                                   skipResults,
                                                   maxResults);
        .../...


Am I right in my understanding ?

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }



Re: Problem with JPetStore

Posted by Christopher Oliver <re...@verizon.net>.
Sylvain Wallez wrote:
> Christopher Oliver wrote:
> 
>> Sylvain Wallez wrote:
>>
>>> Christopher Oliver wrote:
>>>
>>>> Sylvain Wallez wrote:
>>>>
>>
>> The call frames that represent the calls to f() and g() are shared 
>> between all continuations captured inside h(). But when a continuation 
>> escapes the while loop and returns to g(), then, at that point, a copy 
>> of the call frame of g() is made, and so on as you return up the stack. 
> 
> 
> 
> Ah, I understand : common stack frames are shared between continuations 
> having the same ancestor continuations.

Yes.

> 
>>> Also, how can local variables be shared between continuations if 
>>> their value changes between calls to sendPageAndWait, as is the case 
>>> of producList ? Isn't it contradictory with the continuation concept 
>>> which should restore variable values ?
>>
>>
>>
>> No. That's the intended behavior - just like in Scheme. Invoking a 
>> continuation only restores the program counter. It does not roll back 
>> changes to other data. That behavior would be way too expensive! As it 
>> is the cost of invoking a continuation is negligable.
> 
> 
> 
> Mmmmh... I guess what you mean here is that the PC and the stack frame 
> are restored, which also includes local variables. What isn't restored 
> is the state of objects pointed by these local variables.

Yes.

> 
> Does JavaScript, like Java, make a difference between primitive types 
> (stored by value on the stack) and object types (stored by reference) ? 
> My understanding after some tests is that a difference is made.
> 

No, there shouldn't be any difference. If there is, it's a bug. What was 
your test?


Re: Problem with JPetStore

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Christopher Oliver wrote:

> Sylvain Wallez wrote:
>
>> Christopher Oliver wrote:
>>
>>> Sylvain Wallez wrote:
>>>
>>>> Moreover, AFAIU, the "productList" variable in viewCategory() is 
>>>> stored in the continuation, and so if we hit "next" and then 
>>>> "prev", the first list exists twice (in different continuations). 
>>>> Isn't there a potential memory consumption problem ? I know 
>>>> continuations expire, but withing the expiration delay, all these 
>>>> lists keep floating around...
>>>
>>>
>>> Yes, but the only things that are really duplicated are the program 
>>> counter and stack frames, and even the stack itself is lazily 
>>> copied. The local variables themselves (like productList) are shared 
>>> between continuations.
>>
>>
>> What do you mean by "lazily copied" ? Doesn't it need to be actually 
>> copied to be stored ?
>
>
> What I mean is if you have a call chain:
>
> function f() {
>    g();
> }
>
> function g() {
>    h();
> }
>
> function h() {
>    while (true) {
>       sendPage(...);
>    }
> }
>
> The call frames that represent the calls to f() and g() are shared 
> between all continuations captured inside h(). But when a continuation 
> escapes the while loop and returns to g(), then, at that point, a copy 
> of the call frame of g() is made, and so on as you return up the stack. 


Ah, I understand : common stack frames are shared between continuations 
having the same ancestor continuations.

>> Also, how can local variables be shared between continuations if 
>> their value changes between calls to sendPageAndWait, as is the case 
>> of producList ? Isn't it contradictory with the continuation concept 
>> which should restore variable values ?
>
>
> No. That's the intended behavior - just like in Scheme. Invoking a 
> continuation only restores the program counter. It does not roll back 
> changes to other data. That behavior would be way too expensive! As it 
> is the cost of invoking a continuation is negligable.


Mmmmh... I guess what you mean here is that the PC and the stack frame 
are restored, which also includes local variables. What isn't restored 
is the state of objects pointed by these local variables.

Does JavaScript, like Java, make a difference between primitive types 
(stored by value on the stack) and object types (stored by reference) ? 
My understanding after some tests is that a difference is made.

>> Sorry for these newbie questions. Is there any docs that explains all 
>> this ? If found your post about JavaScript for Java programmers but 
>> it doesn't give any details about this.
>
>
> http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=102781075226697&w=2


Wikified at 
http://wiki.cocoondev.org/Wiki.jsp?page=RhinoWithContinuations !!

Thanks,
Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }



Re: Problem with JPetStore

Posted by Christopher Oliver <re...@verizon.net>.
Sylvain Wallez wrote:
> Christopher Oliver wrote:
> 
>> Sylvain Wallez wrote:
>>> Moreover, AFAIU, the "productList" variable in viewCategory() is 
>>> stored in the continuation, and so if we hit "next" and then "prev", 
>>> the first list exists twice (in different continuations). Isn't there 
>>> a potential memory consumption problem ? I know continuations expire, 
>>> but withing the expiration delay, all these lists keep floating 
>>> around...
>>>
>>
>> Yes, but the only things that are really duplicated are the program 
>> counter and stack frames, and even the stack itself is lazily copied. 
>> The local variables themselves (like productList) are shared between 
>> continuations.
> 
> 
> 
> What do you mean by "lazily copied" ? Doesn't it need to be actually 
> copied to be stored ?

What I mean is if you have a call chain:

function f() {
    g();
}

function g() {
    h();
}

function h() {
    while (true) {
       sendPage(...);
    }
}

The call frames that represent the calls to f() and g() are shared 
between all continuations captured inside h(). But when a continuation 
escapes the while loop and returns to g(), then, at that point, a copy 
of the call frame of g() is made, and so on as you return up the stack.

> 
> Also, how can local variables be shared between continuations if their 
> value changes between calls to sendPageAndWait, as is the case of 
> producList ? Isn't it contradictory with the continuation concept which 
> should restore variable values ?

No. That's the intended behavior - just like in Scheme. Invoking a 
continuation only restores the program counter. It does not roll back 
changes to other data. That behavior would be way too expensive! As it 
is the cost of invoking a continuation is negligable.

> 
> Sorry for these newbie questions. Is there any docs that explains all 
> this ? If found your post about JavaScript for Java programmers but it 
> doesn't give any details about this.

http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=102781075226697&w=2

> 
> Also, how are handled global variables ? AFAIU calling createSession() 
> "attaches" them to the session, but what if createSession() isn't called ?
> 
Then a new fresh set are created each time.

> And what is the relationship between global variables and continuations ?
> 

No special relationship: global variables are accessible in 
continuations as are local variables.


Re: Problem with JPetStore

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
Christopher Oliver wrote:

> Sylvain Wallez wrote:
>
>> Hi,
>>
>> I'm playing and digging in flow-enabled petstore (BTW, so nice, I 
>> love it), and experienced some problems with the 
>> continutation-enabled prev/next navigation.
>>
>> To reproduce it, go to the "dogs" area, click "next" once and then 
>> hit the browser's reload button. The prev and next links are now 
>> totally screwed.
>>
>> Any ideas on what's going on ?
>
>
> Yep. It's a bug. Here's a fix: 


Thanks :)

>>
>> Moreover, AFAIU, the "productList" variable in viewCategory() is 
>> stored in the continuation, and so if we hit "next" and then "prev", 
>> the first list exists twice (in different continuations). Isn't there 
>> a potential memory consumption problem ? I know continuations expire, 
>> but withing the expiration delay, all these lists keep floating 
>> around...
>>
>
> Yes, but the only things that are really duplicated are the program 
> counter and stack frames, and even the stack itself is lazily copied. 
> The local variables themselves (like productList) are shared between 
> continuations.


What do you mean by "lazily copied" ? Doesn't it need to be actually 
copied to be stored ?

Also, how can local variables be shared between continuations if their 
value changes between calls to sendPageAndWait, as is the case of 
producList ? Isn't it contradictory with the continuation concept which 
should restore variable values ?

Sorry for these newbie questions. Is there any docs that explains all 
this ? If found your post about JavaScript for Java programmers but it 
doesn't give any details about this.

Also, how are handled global variables ? AFAIU calling createSession() 
"attaches" them to the session, but what if createSession() isn't called ?

And what is the relationship between global variables and continuations ?

> That being said, it is still possible to explicitly free memory when a 
> continuation is captured, using this extended JavaScript syntax:


<snip-example/>

Thanks for your explanations,
Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }



Re: Problem with JPetStore

Posted by Christopher Oliver <re...@verizon.net>.
Sylvain Wallez wrote:
> Hi,
> 
> I'm playing and digging in flow-enabled petstore (BTW, so nice, I love 
> it), and experienced some problems with the continutation-enabled 
> prev/next navigation.
> 
> To reproduce it, go to the "dogs" area, click "next" once and then hit 
> the browser's reload button. The prev and next links are now totally 
> screwed.
> 
> Any ideas on what's going on ?

Yep. It's a bug. Here's a fix:

function viewCategory() {
     var categoryId = cocoon.request.get("categoryId");
     var category = getPetStore().getCategory(categoryId);
     var skipResults = 0;
     var maxResults = MAX_RESULTS;
     while (true) {
         var productList = 
getPetStore().getProductListByCategory(categoryId,
 
skipResults,
 
maxResults);
         sendPageAndWait("/view/Category.html", {
                         accountForm: accountForm,
                         productList: productList.rows,
                         category: category,
                         firstPage: skipResults == 0,
                         lastPage: !productList.isLimitedByMaxRows
         });
         var page = cocoon.request.get("page");
         if (page == "previous") {
	    if (skipResults != 0) {
		skipResults -= maxResults;
	    }
         } else if (page == "next") {
	    if (!productList.isLimitedByMaxRows) {
		skipResults += productList.rowCount;
	    }
         }
     }
}
> 
> Moreover, AFAIU, the "productList" variable in viewCategory() is stored 
> in the continuation, and so if we hit "next" and then "prev", the first 
> list exists twice (in different continuations). Isn't there a potential 
> memory consumption problem ? I know continuations expire, but withing 
> the expiration delay, all these lists keep floating around...
> 

Yes, but the only things that are really duplicated are the program 
counter and stack frames, and even the stack itself is lazily copied. 
The local variables themselves (like productList) are shared between 
continuations.

That being said, it is still possible to explicitly free memory when a 
continuation is captured, using this extended JavaScript syntax:

catch (break) {
    // the continuation I'm part of is about to be captured
    // code to handle that goes here
}

catch (continue) {
    // the continuation I'm part of is about to be resumed
    // code to handle that goes here
}


For example you could get rid of productList like this:

function viewCategory() {
     var categoryId = cocoon.request.get("categoryId");
     var category = getPetStore().getCategory(categoryId);
     var skipResults = 0;
     var maxResults = MAX_RESULTS;
     while (true) {
         var productList = 
getPetStore().getProductListByCategory(categoryId,
 
skipResults,
 
maxResults);
	var lastPage = !productList.isLimitedByMaxRows;
	var rowCount = productList.rowCount;
         sendPageAndWait("/view/Category.html", {
                         accountForm: accountForm,
                         productList: productList.rows,
                         category: category,
                         firstPage: skipResults == 0,
                         lastPage: lastPage
         });
	catch (break) {
             // zap product list before returning
             // page to browser
             print("zapping productList");
	    productList = null;
	}
         catch (continue) {
             print("return from continuation");
             print("productList = " + productList);
         }
         var page = cocoon.request.get("page");
         if (page == "previous") {
	    if (skipResults != 0) {
		skipResults -= maxResults;
	    }
         } else if (page == "next") {
	    if (!lastPage) {
		skipResults += rowCount;
	    }
         }
     }
}