ICEfaces
  1. ICEfaces
  2. ICE-8833

Session leak in SessionMonitors

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: EE-1.8.2.GA_P05
    • Fix Version/s: EE-1.8.2.GA_P06
    • Component/s: None
    • Labels:
      None
    • Environment:
      icefaces-1.8.2 revision 32630 from trunk, tomcat 6.0.32, jdk 1.6_027
    • Assignee Priority:
      P2

      Description

      SessionDispatcher do not remove invalidated sessions from Map.
      In worst case users notice thousands of unused session objects (some old Jira issues I saw here).
      I attached file SessionDispatcher.java with additional logger messages.

      Test case.
      Prepare app with form-login for basic authentication and logout button.
      If you logon and logout few times 'Session Monitor session count' grows and many 'session already invalidated' messages occurs every 10 seconds..

      The main reason is line:
         iterator = new ArrayList(SessionMonitors.values()).iterator();
      Session cleaner do not clean correct list.
      After change to
         iterator = SessionMonitors.values().iterator();
      everything seems to be ok and sessions are removed.
      1. SessionDispatcher.java
        21 kB
        Krashan Brahmanjara
      2. SessionDispatcher.java
        20 kB
        Krashan Brahmanjara
      3. SessionDispatcher.java
        20 kB
        Krashan Brahmanjara
      4. sessionerrors.txt
        4 kB
        Krashan Brahmanjara
      5. sessionlog.txt
        2 kB
        Krashan Brahmanjara
      6. sessionlog2.txt
        3 kB
        Krashan Brahmanjara
      7. sessionlog3.txt
        3 kB
        Krashan Brahmanjara
      8. web.xml
        11 kB
        Krashan Brahmanjara
      1. sessionproblems.PNG
        85 kB

        Activity

        Hide
        Krashan Brahmanjara added a comment -

        Patched SessionDispatcher.

        Show
        Krashan Brahmanjara added a comment - Patched SessionDispatcher.
        Hide
        Krashan Brahmanjara added a comment -

        messages printed every 10 second after three logon and logout steps

        Show
        Krashan Brahmanjara added a comment - messages printed every 10 second after three logon and logout steps
        Hide
        Krashan Brahmanjara added a comment - - edited

        Second test with ~12 login and logouts.
        Unfortunately patch attached in Description section do not help in this case.

        I see 13 sessions in Map, 3 already invalidated are still in Monitor (until web.xml session-timeout expiration)

        What kind of action should be called on logout? I suppose old fashion logout code like below do not always work correct with SessionMonitors.

        FacesContext fc = FacesContext.getCurrentInstance();
        final ExternalContext ec = fc.getExternalContext();

        new Thread() {
        @Override
        public void run()

        { ((HttpSession) ec.getSession(false)).invalidate(); }

        }.start();

        Show
        Krashan Brahmanjara added a comment - - edited Second test with ~12 login and logouts. Unfortunately patch attached in Description section do not help in this case. I see 13 sessions in Map, 3 already invalidated are still in Monitor (until web.xml session-timeout expiration) What kind of action should be called on logout? I suppose old fashion logout code like below do not always work correct with SessionMonitors. FacesContext fc = FacesContext.getCurrentInstance(); final ExternalContext ec = fc.getExternalContext(); new Thread() { @Override public void run() { ((HttpSession) ec.getSession(false)).invalidate(); } }.start();
        Hide
        Krashan Brahmanjara added a comment -

        BTW. Patch added with ICE-8663 do not help.

        Show
        Krashan Brahmanjara added a comment - BTW. Patch added with ICE-8663 do not help.
        Hide
        Krashan Brahmanjara added a comment - - edited

        Added new patched SessionDispatcher (at 16/Dec/12), improved version.
        Added diagnostic loggers, real session key as a field of Monitor and SessionMonitors.remove for session already invalidated.

        Show
        Krashan Brahmanjara added a comment - - edited Added new patched SessionDispatcher (at 16/Dec/12), improved version. Added diagnostic loggers, real session key as a field of Monitor and SessionMonitors.remove for session already invalidated.
        Hide
        Krashan Brahmanjara added a comment -

        Added sessionlog3 with results for test with last patch for SessionDispatched.
        Session in log was successfully removed by real key from SessionMonitors map in case when notifySessionShutdown can't do it because it looking for unknown sessionid .

        Show
        Krashan Brahmanjara added a comment - Added sessionlog3 with results for test with last patch for SessionDispatched. Session in log was successfully removed by real key from SessionMonitors map in case when notifySessionShutdown can't do it because it looking for unknown sessionid .
        Hide
        Krashan Brahmanjara added a comment -

        Atached image sessionproblems.png.
        As you can see key from map can be not equal to session.id. So removing monitors from map using session.id sometimes fails.

        Show
        Krashan Brahmanjara added a comment - Atached image sessionproblems.png. As you can see key from map can be not equal to session.id. So removing monitors from map using session.id sometimes fails.
        Hide
        Krashan Brahmanjara added a comment - - edited

        I don't know primary concept of SessionDispatcher but summary it looks like problem with sessionId. Another one is registered in SessionMonitors by checkSession method and another one can be used later by notifySessionShutdown. It can occurs on first logon after Tomcat restart.

        In short test with login form and logout with session.invalidate I saw many cases.
        For example

        • sessionMonitor and notifySessionShutdown use the same session id and sessionMonitor is correctly cleared on session.invalidate
        • sessionMonitor and notifySessionShutdown use the same session id and sessionMonitor is correctly cleared on session-timeout
        • sessionMonitor and notifySessionShutdown use the different keys and sessionMonitor is not correctly cleared on session.invalidate
        • sessionMonitor and notifySessionShutdown use the different keys and sessionMonitor is not correctly cleared on session-timeout ...live forever
        • sessionMonitor and notifySessionShutdown use the different keys and the same session id is registered in two (or more?) Monitors

        So mine last patch resolved some of our maintenance problems but should be verified with icefaces authors.

        Show
        Krashan Brahmanjara added a comment - - edited I don't know primary concept of SessionDispatcher but summary it looks like problem with sessionId. Another one is registered in SessionMonitors by checkSession method and another one can be used later by notifySessionShutdown. It can occurs on first logon after Tomcat restart. In short test with login form and logout with session.invalidate I saw many cases. For example sessionMonitor and notifySessionShutdown use the same session id and sessionMonitor is correctly cleared on session.invalidate sessionMonitor and notifySessionShutdown use the same session id and sessionMonitor is correctly cleared on session-timeout sessionMonitor and notifySessionShutdown use the different keys and sessionMonitor is not correctly cleared on session.invalidate sessionMonitor and notifySessionShutdown use the different keys and sessionMonitor is not correctly cleared on session-timeout ...live forever sessionMonitor and notifySessionShutdown use the different keys and the same session id is registered in two (or more?) Monitors So mine last patch resolved some of our maintenance problems but should be verified with icefaces authors.
        Hide
        Krashan Brahmanjara added a comment - - edited

        Another side of the same story. Icefaces Forum "recommend" two very old solutions for logout action.

        First one seem to be invalid and is partially responsible for "ghost" session multiplication in SessionMonitor.
        In ICE-5997 Deryk Sinotte wrote about similar behaviour.

          <ice:comandLink action="#{logoutAction}" ...>
        
          public String logoutAction() {
            FacesContext fc = FacesContext.getCurrentInstance();
            final ExternalContext ec = fc.getExternalContext();
            new Thread() {
              @Override
              public void run() {
                ((HttpSession) ec.getSession(false)).invalidate();
              }
            }.start();
            return "index";
          }
        

        Second one is much better with low number of new and "ghost" sessions in monitor

          <ice:outputLink value="logout.jsp" ..>
        
          logout.jsp
          <% 
          session.invalidate();
          RequestDispatcher reqObj = request.getRequestDispatcher("/index.jsp");
          if (reqObj != null) {
            reqObj.forward(request, response);
          }else {
            response.sendRedirect(request.getContextPath()+"/index.jsp");
          }
          %>
        

        Summary. Core patch and logout patch get acceptable results.

        Show
        Krashan Brahmanjara added a comment - - edited Another side of the same story. Icefaces Forum "recommend" two very old solutions for logout action. First one seem to be invalid and is partially responsible for "ghost" session multiplication in SessionMonitor. In ICE-5997 Deryk Sinotte wrote about similar behaviour. <ice:comandLink action= "#{logoutAction}" ...> public String logoutAction() { FacesContext fc = FacesContext.getCurrentInstance(); final ExternalContext ec = fc.getExternalContext(); new Thread () { @Override public void run() { ((HttpSession) ec.getSession( false )).invalidate(); } }.start(); return "index" ; } Second one is much better with low number of new and "ghost" sessions in monitor <ice:outputLink value= "logout.jsp" ..> logout.jsp <% session.invalidate(); RequestDispatcher reqObj = request.getRequestDispatcher( "/index.jsp" ); if (reqObj != null ) { reqObj.forward(request, response); } else { response.sendRedirect(request.getContextPath()+ "/index.jsp" ); } %> Summary. Core patch and logout patch get acceptable results.
        Hide
        Mircea Toma added a comment -

        It seems that the memory leak is caused by the 'receive-updates' requests that arrive to the server after the session was invalidated, thus causing the SessionDispatcher to create a new session with its corresponding SessionMonitor and session bound server. The requests are triggered by the last notification sent by the server before it shuts down the session, this notification is meant to inform all the participating windows that the session expired/was invalidated.

        Show
        Mircea Toma added a comment - It seems that the memory leak is caused by the 'receive-updates' requests that arrive to the server after the session was invalidated, thus causing the SessionDispatcher to create a new session with its corresponding SessionMonitor and session bound server. The requests are triggered by the last notification sent by the server before it shuts down the session, this notification is meant to inform all the participating windows that the session expired/was invalidated.
        Hide
        Mircea Toma added a comment -

        Modified InterceptingServletSession to invalidate the session right away instead of waiting for the JSF cycle to complete. Modified MainSessionBoundServlet to dispose the view and its associated FacesContext only after the JSF lifecycle ended to avoid NPEs in JSF or application code. Modified corresponding servers for 'receive-updates' and 'send-receive-updates' requests to capture SessionExpiredException (thown when an expired session is accessed) and respond with the session-expired message. Modified MainServlet to respond with the session expired message when the incoming AJAX requests belong to an invalidated session.

        All these modification are meant to avoid the re-creation of a new session after the session was just invalidated.

        Show
        Mircea Toma added a comment - Modified InterceptingServletSession to invalidate the session right away instead of waiting for the JSF cycle to complete. Modified MainSessionBoundServlet to dispose the view and its associated FacesContext only after the JSF lifecycle ended to avoid NPEs in JSF or application code. Modified corresponding servers for 'receive-updates' and 'send-receive-updates' requests to capture SessionExpiredException (thown when an expired session is accessed) and respond with the session-expired message. Modified MainServlet to respond with the session expired message when the incoming AJAX requests belong to an invalidated session. All these modification are meant to avoid the re-creation of a new session after the session was just invalidated.
        Hide
        Mircea Toma added a comment -

        The changes were tested with component-showcase configured to use form based authentication with multiple windows. Also tested the session expiration with multiple windows to make sure the 'session-expired' notification gets received by all the windows.

        Show
        Mircea Toma added a comment - The changes were tested with component-showcase configured to use form based authentication with multiple windows. Also tested the session expiration with multiple windows to make sure the 'session-expired' notification gets received by all the windows.
        Hide
        Krashan Brahmanjara added a comment -

        Thanks for quick response. I merged your patch with my loggers and I still see SessionMonitor items unrelated with sessionId and messages "Session already invalidated"
        It seems to me it work much better only with logoutAction() scenario.

        Details in attachment sessionerrors.txt
        cases:
        '#invalidated sessions still exist in SessionMonitor'
        '#invalidated sessions still exist in SessionMonitor and was not removed after log pause (pause with hibernation)'

        Finally I merge also my 'key' fix and now I only see case '#key not equal session id' and it seems to be OK.

        Show
        Krashan Brahmanjara added a comment - Thanks for quick response. I merged your patch with my loggers and I still see SessionMonitor items unrelated with sessionId and messages "Session already invalidated" It seems to me it work much better only with logoutAction() scenario. Details in attachment sessionerrors.txt cases: '#invalidated sessions still exist in SessionMonitor' '#invalidated sessions still exist in SessionMonitor and was not removed after log pause (pause with hibernation)' Finally I merge also my 'key' fix and now I only see case '#key not equal session id' and it seems to be OK.
        Hide
        Krashan Brahmanjara added a comment - - edited

        Added sessionerrors.txt file with three problem examples

        Show
        Krashan Brahmanjara added a comment - - edited Added sessionerrors.txt file with three problem examples
        Hide
        Krashan Brahmanjara added a comment - - edited

        Added SessionDispatched.java with 'key' fix and Mircea Toma last changes

        Show
        Krashan Brahmanjara added a comment - - edited Added SessionDispatched.java with 'key' fix and Mircea Toma last changes
        Hide
        Deryk Sinotte added a comment -

        Please review last comments to ensure our fix is valid and complete.

        Show
        Deryk Sinotte added a comment - Please review last comments to ensure our fix is valid and complete.
        Hide
        Krashan Brahmanjara added a comment - - edited

        Last three post was verified with complex application based of last Icefaces 1.8 from trunk. My web.xml in attachment.
        I took clean copy of SessionDispatcher and merged it with my logger messages.
        After this I still saw SessionMonitor items with key not equal to sessionId and they can never be removed from the map (even after invalidation by Tomcat engine like in sessionerrors.txt).
        My additional patch was necessary to pass performance and memory leaks tests

        Show
        Krashan Brahmanjara added a comment - - edited Last three post was verified with complex application based of last Icefaces 1.8 from trunk. My web.xml in attachment. I took clean copy of SessionDispatcher and merged it with my logger messages. After this I still saw SessionMonitor items with key not equal to sessionId and they can never be removed from the map (even after invalidation by Tomcat engine like in sessionerrors.txt). My additional patch was necessary to pass performance and memory leaks tests
        Hide
        Mircea Toma added a comment -

        Applied (slightly modified) patch provided by Krashan. The fix modifies Monitor class to removes itself from the list of running monitors when invalidating an expired session. Also, changed getId() to a static method so that it can be used in all the places where the session ID is required.

        The fix was tested in following scenarios:
        A) natural session expiry
        B) invalidated after accessing the app through a login form
        C) application redeploy while session still valid
        D) waking up the machine, after being put to sleep while the session still valid

        In all the cases there were no SessionMonitor instances being left in the list of session monitors.

        Show
        Mircea Toma added a comment - Applied (slightly modified) patch provided by Krashan. The fix modifies Monitor class to removes itself from the list of running monitors when invalidating an expired session. Also, changed getId() to a static method so that it can be used in all the places where the session ID is required. The fix was tested in following scenarios: A) natural session expiry B) invalidated after accessing the app through a login form C) application redeploy while session still valid D) waking up the machine, after being put to sleep while the session still valid In all the cases there were no SessionMonitor instances being left in the list of session monitors.
        Hide
        Krashan Brahmanjara added a comment -

        Improved version works perfectly.

        Show
        Krashan Brahmanjara added a comment - Improved version works perfectly.

          People

          • Assignee:
            Mircea Toma
            Reporter:
            Krashan Brahmanjara
          • Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: