diff --git a/java/org/apache/catalina/ha/session/DeltaManager.java b/java/org/apache/catalina/ha/session/DeltaManager.java index f6a8269735ab..b7a9b2c26e6c 100644 --- a/java/org/apache/catalina/ha/session/DeltaManager.java +++ b/java/org/apache/catalina/ha/session/DeltaManager.java @@ -841,6 +841,7 @@ public synchronized void getAllClusterSessions() { counterSend_EVT_GET_ALL_SESSIONS.incrementAndGet(); } stateTransferred = false; + noContextManagerReceived = false; // FIXME This send call block the deploy thread, when sender waitForAck is enabled try { synchronized (receivedMessageQueue) { diff --git a/test/org/apache/catalina/ha/session/TestDeltaManagerStateTransfer.java b/test/org/apache/catalina/ha/session/TestDeltaManagerStateTransfer.java new file mode 100644 index 000000000000..0c1c0d7f778a --- /dev/null +++ b/test/org/apache/catalina/ha/session/TestDeltaManagerStateTransfer.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.ha.session; + +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Test; + +import org.apache.catalina.ha.CatalinaCluster; +import org.apache.catalina.tribes.Member; + +/** + * Tests that {@link DeltaManager#getAllClusterSessions()} resets the + * {@code noContextManagerReceived} flag before requesting session state. If + * the flag is not reset, a previously received + * {@code EVT_ALL_SESSION_NOCONTEXTMANAGER} causes the state transfer wait to + * exit immediately on every subsequent request, even when the cluster node + * now has a context manager and sends session state. + */ +public class TestDeltaManagerStateTransfer { + + private static CatalinaCluster createClusterWithOneMember() { + // findSessionMasterMember() uses members[0] as the state transfer + // source so the array must contain a non-null member. + Member member = EasyMock.createNiceMock(Member.class); + CatalinaCluster cluster = EasyMock.createNiceMock(CatalinaCluster.class); + EasyMock.expect(cluster.getMembers()).andReturn(new Member[] { member }).anyTimes(); + // send() is a void method: a nice mock performs no action. + EasyMock.replay(cluster); + return cluster; + } + + @Test + public void testNoContextManagerFlagResetOnNewStateRequest() throws Exception { + DeltaManager manager = new DeltaManager(); + manager.setCluster(createClusterWithOneMember()); + // Keep the wait short: the test does not provide a real reply so the + // wait will end via the timeout path. + manager.setStateTransferTimeout(1); + + // Simulate a previously received EVT_ALL_SESSION_NOCONTEXTMANAGER + manager.setNoContextManagerReceived(true); + + manager.getAllClusterSessions(); + + // The new state request must reset the flag so the wait is not + // skipped immediately on this and subsequent transfers. + Assert.assertFalse("noContextManagerReceived should be reset when requesting session state", + manager.isNoContextManagerReceived()); + } + + @Test + public void testStateTransferredResetOnNewStateRequest() throws Exception { + DeltaManager manager = new DeltaManager(); + manager.setCluster(createClusterWithOneMember()); + manager.setStateTransferTimeout(1); + + // Simulate a completed previous transfer + manager.setStateTransferred(true); + + manager.getAllClusterSessions(); + + Assert.assertFalse("stateTransferred should be reset when requesting session state", + manager.getStateTransferred()); + } +} diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index a72a483a4ddc..3239c10d24ce 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -344,6 +344,13 @@ NegativeArraySizeException during session state transfer. Pull request 1042 provided by lihongyi87. (markt) + + Ensure DeltaManager resets the + noContextManagerReceived flag when requesting session + state. A previously received ALL_SESSION_NOCONTEXTMANAGER + event caused all subsequent state transfers to return immediately, + skipping sessions sent by the cluster. (lihongyi87) +