Bug 56578

Summary: session.invalidate does not work on cluster enabled webapps
Product: Tomcat 7 Reporter: David Rees <drees76>
Component: ClusterAssignee: Tomcat Developers Mailing List <dev>
Severity: blocker    
Priority: P2    
Version: 7.0.54   
Target Milestone: ---   
Hardware: All   
OS: Linux   
Attachments: session.jsp

Description David Rees 2014-05-30 01:24:18 UTC
session invalidate does not work in 7.0.54 when Tomcat is clustered. 7.0.53 is OK.

Steps to reproduce:

1. Use Clustered Tomcat, with the following added to the <Host/> in server.xml:

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

2. Drop session.jsp and invalidate.jsp from attachments into a directory.

3. Open session.jsp in a browser. Note creation time.

4. Refresh page and note creation time stays the same.

5. Click on Invalidate and note that creation time is updated.

On Tomcat 7.0.53 all steps above succeed.
On Tomcat 7.0.54 step 5 fails.
Comment 1 David Rees 2014-05-30 01:24:52 UTC
Created attachment 31678 [details]
Comment 2 David Rees 2014-05-30 01:25:04 UTC
Created attachment 31679 [details]
Comment 3 Konstantin Kolinko 2014-05-30 13:11:08 UTC
For reference: the thread on users@,
"Tomcat 7.0.54 - Session invalidate broken in some apps"
Comment 4 Konstantin Kolinko 2014-05-30 23:19:08 UTC

I placed both files into webapps/examples/
I added the following line to session.jsp to display current session id:
<tr><td>Session ID:</td><td><%= session.getId() %></td></tr>

I am using a single Tomcat instance, with default configuration.
I added the following line added to server.xml.
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

I do not see any error. The session creation time is updated on invalidation, and session id is changed as well.

Tested with current 7.0.x (JDK 6u45) and 8.0.x (JDK 7u55),
on Win7, Firefox 29.0.1,

A fragment of catalina.date.log of Tomcat 7 (at start time):

31.05.2014 0:02:35 org.apache.catalina.ha.tcp.SimpleTcpCluster startInternal
INFO: Cluster is about to start
31.05.2014 0:02:35 org.apache.catalina.tribes.transport.ReceiverBase bind
INFO: Receiver Server Socket bound to:/xxx.yyy.z.www:4000
31.05.2014 0:02:35 org.apache.catalina.tribes.membership.McastServiceImpl setupSocket
INFO: Setting cluster mcast soTimeout to 500
31.05.2014 0:02:35 org.apache.catalina.tribes.membership.McastServiceImpl waitForMembers
INFO: Sleeping for 1000 milliseconds to establish cluster membership, start level:4
31.05.2014 0:02:36 org.apache.catalina.tribes.membership.McastServiceImpl waitForMembers
INFO: Done sleeping, membership established, start level:4
31.05.2014 0:02:36 org.apache.catalina.tribes.membership.McastServiceImpl waitForMembers
INFO: Sleeping for 1000 milliseconds to establish cluster membership, start level:8
31.05.2014 0:02:37 org.apache.catalina.tribes.membership.McastServiceImpl waitForMembers
INFO: Done sleeping, membership established, start level:8
31.05.2014 0:02:37 org.apache.catalina.ha.session.JvmRouteBinderValve startInternal
INFO: JvmRouteBinderValve started

Did you use a single Tomcat instance in your reproduction scenario, or I need something more complex?

Did your cluster startup log looked like the above?

Does your configuration have other differences from the default one (besides the added line in server.xml)?

Can you try debugging? (As mentioned in the e-mail thread).
Comment 5 David Rees 2014-05-31 00:22:29 UTC
On a hunch, I tested a webapp with and without the <distributable/> element.

The webapp also needs to have that element in the web.xml to reproduce the issue and the examples webapp does not have it.

FWIW environment is CentOS 6.5, Java 7u55 and Chrome 35, but I don't think any of those factors matter.
Comment 6 Konstantin Kolinko 2014-05-31 12:21:15 UTC
Ack. Thank you!
It is reproducible with 8.0 if I add <distributable/> to examples/WEB-INF/web.xml.

This regression is caused by StandardSession change in r1584915
(a fix to bug 56339)

The session object is DeltaSession.
The sequence of events is:

1. session.invalidate() = StandardSession.invalidate() -> calls expire()
2. expire() is implemented as expire(notify=true)
3. DeltaSession.expire(notify) is implemented as expire(notify=true, notifyCluster=true).

4. DeltaSession.expire(boolean notify, boolean notifyCluster)
- sets "expiring = true"
- does cluster.send(msg);
- calls super.expire(notify);

Here the things go wrong. Because of the change in r1584915 the StandardSession.expire(notify) checks the "expiring" flag and exits immediately. Effectively that call became a NOOP.

Thus the actual expiration does not happen.
Comment 7 David Rees 2014-05-31 16:37:11 UTC
Thank you for tracking it down. That was one of the possible suspects I had looked at while reviewing the changelog for possible regressions.
Comment 8 Mark Thomas 2014-06-06 10:34:13 UTC
This has been fixed in 8.0.x for 8.0.9 onwards and in 7.0.x for 7.0.55 onwards.