You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Joerg Heinicke <jo...@gmx.de> on 2005/05/10 18:56:01 UTC

[IMP] synchronization on session object in Cocoon

Hello,

I think I have found a more general problem with synchronization in Cocoon. I
tried to solve my problem with synchronization in flow script with an
intermediate object. This object handles the synchronized instantiation of my
component. Unfortunately I found out that "synchronized (session) { ... }" still
did not work - two requests of the same session run into that block at the same
time. I did some remote debugging. First I thought the reason is in flow script
as it also wraps the session, but it unwraps it later. The reason is in
HttpRequest class. Have a look at the code [1]:

public Session getSession(boolean create) {
    javax.servlet.http.HttpSession serverSession = this.req.getSession(create);
    if ( null != serverSession) {
        if ( null != this.session ) {
            if ( this.session.wrappedSession != serverSession ) {
                // update wrapper
                this.session.wrappedSession = serverSession;
            }
        } else {
            // new wrapper
            this.session = new HttpSession( serverSession );
        }
    } else {
        // invalidate
        this.session = null;
    }
    return this.session;
}

As you can see on every request a new wrapper is instantiated which is really
bad. It is not possible to synchronize on Cocoon session objects. What we
probably need is a Map mapping the server sessions to the wrapper objects.

WDYT?

Joerg

[1] http://svn.apache.org/viewcvs.cgi/cocoon/tags/RELEASE_2_1_7/src/java/org/
apache/cocoon/environment/http/HttpRequest.java?rev=158761&view=markup


Re: [IMP] synchronization on session object in Cocoon

Posted by Joerg Heinicke <jo...@gmx.de>.
Sylvain Wallez <sylvain <at> apache.org> writes:

> This approach has the problem of entering a synchronized block each time 
> getSession is called. Although this may not that be much a problem in 
> this particular case because it's unlikely that many parallel requests 
> exist for a single request, we may totally avoid it except once.

http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double_p.html

Joerg


Re: [IMP] synchronization on session object in Cocoon

Posted by Sylvain Wallez <sy...@apache.org>.
Joerg Heinicke wrote:

>Sylvain Wallez <sylvain <at> apache.org> writes:
>
>  
>
>>>I think I have found a more general problem with synchronization in Cocoon. I
>>>tried to solve my problem with synchronization in flow script with an
>>>intermediate object. This object handles the synchronized instantiation of my
>>>component. Unfortunately I found out that "synchronized (session) { ... }"
>>>still did not work - two requests of the same session run into that block at
>>>the same time. I did some remote debugging. First I thought the reason is in
>>>flow script as it also wraps the session, but it unwraps it later. The reason
>>>is in HttpRequest class. Have a look at the code [1]:
>>>      
>>>
>
>  
>
>>>As you can see on every request a new wrapper is instantiated which is really
>>>bad. It is not possible to synchronize on Cocoon session objects.
>>>      
>>>
>>Wow, very good point!
>>
>>    
>>
>>>What we probably need is a Map mapping the server sessions to the wrapper
>>>objects.
>>> 
>>>      
>>>
>>Or more simply we could store the wrapper in the session itself using an 
>>attribute. That way it would be guaranteed to be created only once.
>>    
>>
>
>Yes, that's another possibility I also had in mind. But on the one hand this
>smells a bit (storing a wrapper in the object that the wrapper wraps), on the
>other hand you can not restrict access to it, so it can be manipulated from
>somewhere else. But the Map solution can indeed be very resource consuming and a
>bottle neck.
>
>I have implemented the session attribute solution. Would be nice if you can
>review it:
>
>public Session getSession(boolean create) {
>    // we must assure a 1:1-mapping of server session to cocoon session
>    javax.servlet.http.HttpSession serverSession = this.req.getSession(create);
>    if (serverSession != null) {
>        synchronized (serverSession) {
>            // retrieve existing wrapper
>            this.session =
>(HttpSession)serverSession.getAttribute(HTTP_SESSION);
>            if (this.session == null) {
>                // create wrapper
>                this.session = new HttpSession(serverSession);
>                serverSession.setAttribute(HTTP_SESSION, this.session);
>            }
>        }
>    } else {
>        // invalidate
>        this.session = null;
>    }
>    return this.session;
>}
>  
>

This approach has the problem of entering a synchronized block each time 
getSession is called. Although this may not that be much a problem in 
this particular case because it's unlikely that many parallel requests 
exist for a single request, we may totally avoid it except once. We also 
no more need to keep the wrapper as "this.session" as the servlet 
session stores the wrapper.

public Session getSession(boolean create) {
    javax.servlet.http.HttpSession serverSession = 
this.req.getSession(create);
    if (serverSession != null) {
        Session session = 
(HttpSession)serverSession.getAttribute(HTTP_SESSION);
        if (session = null) {
            return createSessionWrapper(serverSession);
        } else {
            return session;
        }
    } else {
        return null;
    }
}

private Session createSessionWrapper(HttpSession serverSession) {
    synchronized(serverSession) {
        // recheck in the synchronized section
        Session session = 
(HttpSession)serverSession.getAttribute(HTTP_SESSION);
        if (session = null) {
            session = new HttpSession(serverSession);
            serverSession.setAttribute(HTTP_SESSION, session);
        }
        return session;
    }
}

>An "update wrapper" (which was indeed an "update wrapped session") as in the old
>implementation is IMO no longer necessary as only the server session holds the
>wrapper - if it is a new server session we also must provide a new wrapper.
>
>To avoid or at least recognize manipulation of the session attribute it is maybe
>possible to let Cocoon's HttpSession implement HttpSessionAttributeListener and
>to check on attributeReplaced(HttpSessionBindingEvent) [1] whether the wrapper
>was replaced and not just removed on invalidation of the session. But first this
>is no 100%-solution as someone could first remove and later set the attribute
>and second it is again overhead (the event is triggered on every session
>attribute add/remove/replace).
>AFAICS the HTTPSessionBindingListener [2] does not help as there is no type of
>HttpSessionBindingEvent, just the information that the wrapper was removed - and
>this must happen when the session is invalidated.
>  
>

Sorry, what problem are you trying to solve with having the wrapper 
being notified of updates?

Sylvain

-- 
Sylvain Wallez                        Anyware Technologies
http://apache.org/~sylvain            http://anyware-tech.com
Apache Software Foundation Member     Research & Technology Director


Re: [IMP] synchronization on session object in Cocoon

Posted by Joerg Heinicke <jo...@gmx.de>.
Sylvain Wallez <sylvain <at> apache.org> writes:

> >I think I have found a more general problem with synchronization in Cocoon. I
> >tried to solve my problem with synchronization in flow script with an
> >intermediate object. This object handles the synchronized instantiation of my
> >component. Unfortunately I found out that "synchronized (session) { ... }"
> >still did not work - two requests of the same session run into that block at
> >the same time. I did some remote debugging. First I thought the reason is in
> >flow script as it also wraps the session, but it unwraps it later. The reason
> >is in HttpRequest class. Have a look at the code [1]:

> >As you can see on every request a new wrapper is instantiated which is really
> >bad. It is not possible to synchronize on Cocoon session objects.
> 
> Wow, very good point!
> 
> >What we probably need is a Map mapping the server sessions to the wrapper
> >objects.
> >  
> Or more simply we could store the wrapper in the session itself using an 
> attribute. That way it would be guaranteed to be created only once.

Yes, that's another possibility I also had in mind. But on the one hand this
smells a bit (storing a wrapper in the object that the wrapper wraps), on the
other hand you can not restrict access to it, so it can be manipulated from
somewhere else. But the Map solution can indeed be very resource consuming and a
bottle neck.

I have implemented the session attribute solution. Would be nice if you can
review it:

public Session getSession(boolean create) {
    // we must assure a 1:1-mapping of server session to cocoon session
    javax.servlet.http.HttpSession serverSession = this.req.getSession(create);
    if (serverSession != null) {
        synchronized (serverSession) {
            // retrieve existing wrapper
            this.session =
(HttpSession)serverSession.getAttribute(HTTP_SESSION);
            if (this.session == null) {
                // create wrapper
                this.session = new HttpSession(serverSession);
                serverSession.setAttribute(HTTP_SESSION, this.session);
            }
        }
    } else {
        // invalidate
        this.session = null;
    }
    return this.session;
}

An "update wrapper" (which was indeed an "update wrapped session") as in the old
implementation is IMO no longer necessary as only the server session holds the
wrapper - if it is a new server session we also must provide a new wrapper.

To avoid or at least recognize manipulation of the session attribute it is maybe
possible to let Cocoon's HttpSession implement HttpSessionAttributeListener and
to check on attributeReplaced(HttpSessionBindingEvent) [1] whether the wrapper
was replaced and not just removed on invalidation of the session. But first this
is no 100%-solution as someone could first remove and later set the attribute
and second it is again overhead (the event is triggered on every session
attribute add/remove/replace).
AFAICS the HTTPSessionBindingListener [2] does not help as there is no type of
HttpSessionBindingEvent, just the information that the wrapper was removed - and
this must happen when the session is invalidated.

WDYT?

Joerg

[1] http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/http/
HttpSessionAttributeListener.html
#attributeReplaced(javax.servlet.http.HttpSessionBindingEvent)

[2] http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/http/
HttpSessionBindingListener.html


Re: [IMP] synchronization on session object in Cocoon

Posted by Sylvain Wallez <sy...@apache.org>.
Joerg Heinicke wrote:

>Hello,
>
>I think I have found a more general problem with synchronization in Cocoon. I
>tried to solve my problem with synchronization in flow script with an
>intermediate object. This object handles the synchronized instantiation of my
>component. Unfortunately I found out that "synchronized (session) { ... }" still
>did not work - two requests of the same session run into that block at the same
>time. I did some remote debugging. First I thought the reason is in flow script
>as it also wraps the session, but it unwraps it later. The reason is in
>HttpRequest class. Have a look at the code [1]:
>
>public Session getSession(boolean create) {
>    javax.servlet.http.HttpSession serverSession = this.req.getSession(create);
>    if ( null != serverSession) {
>        if ( null != this.session ) {
>            if ( this.session.wrappedSession != serverSession ) {
>                // update wrapper
>                this.session.wrappedSession = serverSession;
>            }
>        } else {
>            // new wrapper
>            this.session = new HttpSession( serverSession );
>        }
>    } else {
>        // invalidate
>        this.session = null;
>    }
>    return this.session;
>}
>
>As you can see on every request a new wrapper is instantiated which is really
>bad. It is not possible to synchronize on Cocoon session objects.
>

Wow, very good point!

>What we probably need is a Map mapping the server sessions to the wrapper objects.
>  
>

Or more simply we could store the wrapper in the session itself using an 
attribute. That way it would be guaranteed to be created only once.

Sylvain

-- 
Sylvain Wallez                        Anyware Technologies
http://apache.org/~sylvain            http://anyware-tech.com
Apache Software Foundation Member     Research & Technology Director