ICEfaces
  1. ICEfaces
  2. ICE-3073

ICEfaces portlet instances not getting deallocated when session expires or is invalidated

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.7
    • Fix Version/s: 1.7.1
    • Component/s: Framework
    • Labels:
      None
    • Environment:
      Liferay 4.3.4 + Tomcat 6.0.13 (and also JBoss 4.2.1)

      Description

      Each time a user logs into Liferay Portal and visits a portal page with an ICEfaces portlet, a session-based instance of that portlet is allocated by the servlet container. When the session expires or is invalidated, the instance should be deallocated by the servlet container but this isn't happening.

      This can be reproduced with Tomcat 6 or JBoss 4.2.1, but when JBoss is used, some extra error messages appear in the console that I think are related, but might actually be a separate bug -- I'm not sure.

      1. Copy the attached SampleAjaxPush1.war_ file to your $HOME/YourUserName/liferay/deploy folder
      2. Rename SampleAjaxPush1.war_ to SampleAjaxPush1.war
      3. Start Liferay-4.3.4-JBoss-4.2.1-Tomcat bundle
      4. Watch the JBoss console and make sure the WAR hot deploys properly
      5. Start IE7 (should be reproducible with any browser though)
      6. Login to Liferay Portal as test@liferay.com
      7. Create a new portal page named "Ajax Push"
      8. Add the "Customers" and "Bookings" portlets from under the "Samples" category
      9. Click on each customer and make sure Ajax Push is working
      10. Monitor the JBoss console and make sure there are no errors at this point
      11. Sign-out of Liferay Portal
      12. Sign back in to Liferay Portal as test@liferay.com
      13. Click on the "Ajax Push" portal page
      14. Click on one of the customers
      15. Note that in the JBoss console, there should be "Session already invalidated" error messages
      16. Note that killing IE7 browser and signing back in doesn't fix this problem
      17. Repeat steps 11-14 in order to create yet another session "instance" of these portlets
      18. Run the "jboss/bin/shutdown.bat ---shutdown" command
      19. Note that in the JBoss console, each instance of these portlets have not yet been deallocated.

      The instances actually never get deallocated unless the portal shuts down. And the default connection pool size in worker.properties is 10 so not very many sessions can get created before the server gets bogged down.

      Also note the error java.lang.IllegalStateException: getAttributeNames: Session already invalidated after all the sessions are deallocated.

        Activity

        Hide
        Greg Dick added a comment -

        When the user opens the "Ajax Push" portlet page, two portletProxySessions are created, and those are associated with an HttpSession from the user. When the user logs out, he/she is logging out from the Portal Web application. The HttpSession is invalidated, but the SessionDispatcher is not informed via callback, and therefore the ICEfaces core never disposes of the Session.

        When a user application logs out, and that's done entirely from within an ICEfaces servlet, the incoming HttpServlet is wrapped in an InterceptingServletSession, which overrides invalidate() and uses this to notify the SessionDispatcher. In the Portlet example, the request to log out is handled by the Portal application, outside the ICEfaces servlet path which is why this mechanism is subverted.

        The ContextEventRepeater gets notified of the SessionDestroyed event, but the SessionDispatcher is not a client of the repeater. It may be possible to make the Dispatcher an event listener but care must be taken and difficult to verify differences in timing may occur, since the ContextEventRepeater is downstream of the events generated by the SessionDispatcher.

        Show
        Greg Dick added a comment - When the user opens the "Ajax Push" portlet page, two portletProxySessions are created, and those are associated with an HttpSession from the user. When the user logs out, he/she is logging out from the Portal Web application. The HttpSession is invalidated, but the SessionDispatcher is not informed via callback, and therefore the ICEfaces core never disposes of the Session. When a user application logs out, and that's done entirely from within an ICEfaces servlet, the incoming HttpServlet is wrapped in an InterceptingServletSession, which overrides invalidate() and uses this to notify the SessionDispatcher. In the Portlet example, the request to log out is handled by the Portal application, outside the ICEfaces servlet path which is why this mechanism is subverted. The ContextEventRepeater gets notified of the SessionDestroyed event, but the SessionDispatcher is not a client of the repeater. It may be possible to make the Dispatcher an event listener but care must be taken and difficult to verify differences in timing may occur, since the ContextEventRepeater is downstream of the events generated by the SessionDispatcher.
        Hide
        Mircea Toma added a comment -

        I attached a patch for this issue. SessionDispatcher is now notified when the session is invalidated by the portal. It is using the same session shutdown sequence as the one used when session is invalidated internally.

        Show
        Mircea Toma added a comment - I attached a patch for this issue. SessionDispatcher is now notified when the session is invalidated by the portal. It is using the same session shutdown sequence as the one used when session is invalidated internally.
        Hide
        Greg Dick added a comment -

        I found the patch to work fine for the issue of the IllegalStateExceptions. The Views are disposed by the SessionDispatcher who also removes the Session from its SessionMap.

        But the application now had a slightly different problem. There were instances of PersistentFacesState still being rendered when the user interacted with the application in the above way. These were detected by seeing FatalRenderingExceptions in a code branch that tested whether the PFState object was already disposed on entering the execute and render methods.

        It turns out that the threadLocal variable in the PersistentFacesState objects can be set 'entering' the execute and render methods. This is a bit unexpected from the work in 1.7 where we checked threadLocal variable status on exiting the MainServlet and exiting the RunnableRender.run() method. Anyway, if the ThreadLocal is non-null on entry, it's not going to be cleared because an exception is thrown, and the cycle would continue the next time someone interacted with the application.

        I've checked in a couple of lines that clears the PersistentFacesState thread local in this code path.

        Show
        Greg Dick added a comment - I found the patch to work fine for the issue of the IllegalStateExceptions. The Views are disposed by the SessionDispatcher who also removes the Session from its SessionMap. But the application now had a slightly different problem. There were instances of PersistentFacesState still being rendered when the user interacted with the application in the above way. These were detected by seeing FatalRenderingExceptions in a code branch that tested whether the PFState object was already disposed on entering the execute and render methods. It turns out that the threadLocal variable in the PersistentFacesState objects can be set 'entering' the execute and render methods. This is a bit unexpected from the work in 1.7 where we checked threadLocal variable status on exiting the MainServlet and exiting the RunnableRender.run() method. Anyway, if the ThreadLocal is non-null on entry, it's not going to be cleared because an exception is thrown, and the cycle would continue the next time someone interacted with the application. I've checked in a couple of lines that clears the PersistentFacesState thread local in this code path.
        Hide
        Greg Dick added a comment -

        Tested with 1.7 branch.

        Show
        Greg Dick added a comment - Tested with 1.7 branch.
        Hide
        Jarkko Lietolahti added a comment -

        I'm still having issues with long gone http sessions related data keeping in the memory.
        After some load testing the JVM's CMS Old gen is filled to the max and "[com.icesoft.util.MonitorRunner] Failed to run monitor: null" is printed to log.

        Also in a heapdump generated by jmap ( no activity on the server, all users logged out) there are still instances of IceFaces components (and some others too);

        Object Histogram:

        num #instances #bytes Class description
        --------------------------------------------------------------------------
        1: 1128218 562200216 char[]
        2: 66617 220418688 byte[]
        3: 506870 62469240 java.lang.Object[]
        4: 294296 50821464 java.util.HashMap$Entry[]
        5: 1203744 48149760 java.lang.String
        6: 655296 36696576 java.util.HashMap$Entry
        7: 259976 36408944 * ConstMethodKlass
        8: 259976 31209920 * MethodKlass
        9: 477604 26745824 org.apache.xerces.dom.AttrImpl
        10: 20310 24144616 * ConstantPoolKlass
        11: 230341 22112736 org.apache.xerces.dom.ElementImpl
        12: 115115 17497480 java.lang.reflect.Method
        13: 234893 16912296 java.util.HashMap
        14: 20310 16597248 * InstanceKlassKlass
        15: 265972 14311280 * SymbolKlass
        16: 16999 13846848 * ConstantPoolCacheKlass
        17: 64748 10392800 int[]
        18: 23498 9399200 com.icesoft.faces.component.ext.HtmlPanelGrid
        19: 230089 9203560 org.apache.xerces.dom.AttributeMap
        20: 117920 8490240 java.util.LinkedHashMap$Entry
        21: 212176 8487040 java.util.Vector
        22: 141765 6804720 java.util.concurrent.locks.ReentrantLock$NonfairSync
        23: 141572 6795456 java.util.concurrent.ConcurrentHashMap$Segment
        24: 96064 6148096 javax.servlet.jsp.tagext.TagAttributeInfo
        25: 150502 6020080 java.util.ArrayList
        26: 122127 5862096 java.lang.ref.WeakReference
        27: 97606 5465936 java.lang.ref.SoftReference
        28: 96999 5423528 java.lang.String[]
        29: 141572 5104296 java.util.concurrent.ConcurrentHashMap$HashEntry[]
        30: 14951 5023536 com.icesoft.faces.component.ext.HtmlOutputText
        31: 61876 4455072 com.icesoft.faces.context.DOMContext
        32: 48453 4263864 java.util.LinkedHashMap
        33: 7173 4231696 * MethodDataKlass
        34: 43430 4169280 java.beans.MethodDescriptor
        35: 21642 3982128 java.lang.Class
        36: 28371 3631488 java.lang.reflect.Field
        37: 31769 3244968 * System ObjArray
        38: 4271 3143456 com.icesoft.faces.component.selectinputtext.SelectInputText
        39: 64053 3074544 javax.faces.component.UIComponentBase$ChildrenList
        40: 74762 2990480 javax.faces.component.UIComponentBase$AttributesMap
        41: 14178 2495328 org.springframework.beans.GenericTypeAwarePropertyDescriptor
        42: 57954 2318160 com.liferay.portlet.Preference
        43: 25960 2294552 short[]
        44: 16706 2138368 java.beans.PropertyDescriptor
        45: 23432 2062016 java.util.TreeMap$Node
        46: 10719 2058048 com.liferay.portal.model.impl.LayoutImpl

        I'll create another issue to track this issue.

        Show
        Jarkko Lietolahti added a comment - I'm still having issues with long gone http sessions related data keeping in the memory. After some load testing the JVM's CMS Old gen is filled to the max and " [com.icesoft.util.MonitorRunner] Failed to run monitor: null" is printed to log. Also in a heapdump generated by jmap ( no activity on the server, all users logged out) there are still instances of IceFaces components (and some others too); Object Histogram: num #instances #bytes Class description -------------------------------------------------------------------------- 1: 1128218 562200216 char[] 2: 66617 220418688 byte[] 3: 506870 62469240 java.lang.Object[] 4: 294296 50821464 java.util.HashMap$Entry[] 5: 1203744 48149760 java.lang.String 6: 655296 36696576 java.util.HashMap$Entry 7: 259976 36408944 * ConstMethodKlass 8: 259976 31209920 * MethodKlass 9: 477604 26745824 org.apache.xerces.dom.AttrImpl 10: 20310 24144616 * ConstantPoolKlass 11: 230341 22112736 org.apache.xerces.dom.ElementImpl 12: 115115 17497480 java.lang.reflect.Method 13: 234893 16912296 java.util.HashMap 14: 20310 16597248 * InstanceKlassKlass 15: 265972 14311280 * SymbolKlass 16: 16999 13846848 * ConstantPoolCacheKlass 17: 64748 10392800 int[] 18: 23498 9399200 com.icesoft.faces.component.ext.HtmlPanelGrid 19: 230089 9203560 org.apache.xerces.dom.AttributeMap 20: 117920 8490240 java.util.LinkedHashMap$Entry 21: 212176 8487040 java.util.Vector 22: 141765 6804720 java.util.concurrent.locks.ReentrantLock$NonfairSync 23: 141572 6795456 java.util.concurrent.ConcurrentHashMap$Segment 24: 96064 6148096 javax.servlet.jsp.tagext.TagAttributeInfo 25: 150502 6020080 java.util.ArrayList 26: 122127 5862096 java.lang.ref.WeakReference 27: 97606 5465936 java.lang.ref.SoftReference 28: 96999 5423528 java.lang.String[] 29: 141572 5104296 java.util.concurrent.ConcurrentHashMap$HashEntry[] 30: 14951 5023536 com.icesoft.faces.component.ext.HtmlOutputText 31: 61876 4455072 com.icesoft.faces.context.DOMContext 32: 48453 4263864 java.util.LinkedHashMap 33: 7173 4231696 * MethodDataKlass 34: 43430 4169280 java.beans.MethodDescriptor 35: 21642 3982128 java.lang.Class 36: 28371 3631488 java.lang.reflect.Field 37: 31769 3244968 * System ObjArray 38: 4271 3143456 com.icesoft.faces.component.selectinputtext.SelectInputText 39: 64053 3074544 javax.faces.component.UIComponentBase$ChildrenList 40: 74762 2990480 javax.faces.component.UIComponentBase$AttributesMap 41: 14178 2495328 org.springframework.beans.GenericTypeAwarePropertyDescriptor 42: 57954 2318160 com.liferay.portlet.Preference 43: 25960 2294552 short[] 44: 16706 2138368 java.beans.PropertyDescriptor 45: 23432 2062016 java.util.TreeMap$Node 46: 10719 2058048 com.liferay.portal.model.impl.LayoutImpl I'll create another issue to track this issue.

          People

          • Assignee:
            Unassigned
            Reporter:
            Neil Griffin
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: