/*
* 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.activemq.artemis.tests.integration.cluster.distribution;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
import org.apache.activemq.artemis.api.core.client.ClientMessage;
import org.apache.activemq.artemis.api.core.client.ClientProducer;
import org.apache.activemq.artemis.api.core.client.ClientSession;
import org.apache.activemq.artemis.core.server.Bindable;
import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType;
import org.apache.activemq.artemis.core.server.cluster.impl.Redistributor;
import org.apache.activemq.artemis.core.server.group.impl.GroupingHandlerConfiguration;
import org.apache.activemq.artemis.core.server.impl.QueueImpl;
import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy;
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class MessageRedistributionTest extends ClusterTestBase {
private static final IntegrationTestLogger log = IntegrationTestLogger.LOGGER;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
start();
}
private void start() throws Exception {
setupServers();
setRedistributionDelay(0);
}
protected boolean isNetty() {
return false;
}
//https://issues.jboss.org/browse/HORNETQ-1061
@Test
public void testRedistributionWithMessageGroups() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
MessageRedistributionTest.log.info("Doing test");
getServer(0).getConfiguration().setGroupingHandlerConfiguration(new GroupingHandlerConfiguration().setName(new SimpleString("handler")).setType(GroupingHandlerConfiguration.TYPE.LOCAL).setAddress(new SimpleString("queues")));
getServer(1).getConfiguration().setGroupingHandlerConfiguration(new GroupingHandlerConfiguration().setName(new SimpleString("handler")).setType(GroupingHandlerConfiguration.TYPE.REMOTE).setAddress(new SimpleString("queues")));
startServers(0, 1);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
this.
createQueue(0, "queues.testaddress", "queue0", null, false);
createQueue(1, "queues.testaddress", "queue0", null, false);
addConsumer(1, 1, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 0, true);
waitForBindings(1, "queues.testaddress", 1, 1, true);
waitForBindings(0, "queues.testaddress", 1, 1, false);
waitForBindings(1, "queues.testaddress", 1, 0, false);
//send some grouped messages before we add the consumer to node 0 so we guarantee its pinned to node 1
sendWithProperty(0, "queues.testaddress", 10, false, Message.HDR_GROUP_ID, new SimpleString("grp1"));
addConsumer(0, 0, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 1, true);
waitForBindings(0, "queues.testaddress", 1, 1, false);
waitForBindings(1, "queues.testaddress", 1, 1, false);
//now send some non grouped messages
send(0, "queues.testaddress", 10, false, null);
//consume half of the grouped messages from node 1
for (int i = 0; i < 5; i++) {
ClientMessage message = getConsumer(1).receive(1000);
Assert.assertNotNull(message);
message.acknowledge();
Assert.assertNotNull(message.getSimpleStringProperty(Message.HDR_GROUP_ID));
}
//now consume the non grouped messages from node 1 where they are pinned
for (int i = 0; i < 5; i++) {
ClientMessage message = getConsumer(0).receive(5000);
Assert.assertNotNull("" + i, message);
message.acknowledge();
Assert.assertNull(message.getSimpleStringProperty(Message.HDR_GROUP_ID));
}
ClientMessage clientMessage = getConsumer(0).receiveImmediate();
Assert.assertNull(clientMessage);
// i know the last 5 messages consumed won't be acked yet so i wait for 15
waitForMessages(1, "queues.testaddress", 15);
//now removing it will start redistribution but only for non grouped messages
removeConsumer(1);
//consume the non grouped messages
for (int i = 0; i < 5; i++) {
ClientMessage message = getConsumer(0).receive(5000);
if (message == null) {
System.out.println();
}
Assert.assertNotNull("" + i, message);
message.acknowledge();
Assert.assertNull(message.getSimpleStringProperty(Message.HDR_GROUP_ID));
}
clientMessage = getConsumer(0).receiveImmediate();
Assert.assertNull(clientMessage);
removeConsumer(0);
addConsumer(1, 1, "queue0", null);
//now we see the grouped messages are still on the same node
for (int i = 0; i < 5; i++) {
ClientMessage message = getConsumer(1).receive(1000);
Assert.assertNotNull(message);
message.acknowledge();
Assert.assertNotNull(message.getSimpleStringProperty(Message.HDR_GROUP_ID));
}
MessageRedistributionTest.log.info("Test done");
}
//https://issues.jboss.org/browse/HORNETQ-1057
@Test
public void testRedistributionStopsWhenConsumerAdded() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
MessageRedistributionTest.log.info("Doing test");
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, false);
createQueue(1, "queues.testaddress", "queue0", null, false);
createQueue(2, "queues.testaddress", "queue0", null, false);
addConsumer(0, 0, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 0, true);
waitForBindings(2, "queues.testaddress", 1, 0, true);
waitForBindings(0, "queues.testaddress", 2, 0, false);
waitForBindings(1, "queues.testaddress", 2, 1, false);
waitForBindings(2, "queues.testaddress", 2, 1, false);
send(0, "queues.testaddress", 2000, false, null);
removeConsumer(0);
addConsumer(0, 0, "queue0", null);
Bindable bindable = servers[0].getPostOffice().getBinding(new SimpleString("queue0")).getBindable();
String debug = ((QueueImpl) bindable).debug();
Assert.assertFalse(debug.contains(Redistributor.class.getName()));
MessageRedistributionTest.log.info("Test done");
}
@Test
public void testRedistributionWhenConsumerIsClosed() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
MessageRedistributionTest.log.info("Doing test");
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, false);
createQueue(1, "queues.testaddress", "queue0", null, false);
createQueue(2, "queues.testaddress", "queue0", null, false);
addConsumer(0, 0, "queue0", null);
addConsumer(1, 1, "queue0", null);
addConsumer(2, 2, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 1, true);
waitForBindings(2, "queues.testaddress", 1, 1, true);
waitForBindings(0, "queues.testaddress", 2, 2, false);
waitForBindings(1, "queues.testaddress", 2, 2, false);
waitForBindings(2, "queues.testaddress", 2, 2, false);
send(0, "queues.testaddress", 20, false, null);
getReceivedOrder(0);
int[] ids1 = getReceivedOrder(1);
getReceivedOrder(2);
removeConsumer(1);
verifyReceiveRoundRobinInSomeOrderWithCounts(false, ids1, 0, 2);
MessageRedistributionTest.log.info("Test done");
}
@Test
public void testRedistributionWhenConsumerIsClosedDifferentQueues() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, true);
createQueue(1, "queues.testaddress", "queue1", null, true);
createQueue(2, "queues.testaddress", "queue2", null, true);
ClientSession sess0 = sfs[0].createSession();
ClientConsumer consumer0 = sess0.createConsumer("queue0");
ClientSession sess1 = sfs[1].createSession();
ClientConsumer consumer1 = sess1.createConsumer("queue1");
ClientSession sess2 = sfs[2].createSession();
ClientConsumer consumer2 = sess2.createConsumer("queue2");
ClientProducer producer0 = sess0.createProducer("queues.testaddress");
final int NUMBER_OF_MESSAGES = 1000;
for (int i = 0; i < 1000; i++) {
producer0.send(sess0.createMessage(true).putIntProperty("count", i));
}
sess0.start();
sess1.start();
sess2.start();
for (int i = 0; i < NUMBER_OF_MESSAGES; i++) {
ClientMessage msg = consumer0.receive(5000);
Assert.assertNotNull(msg);
msg.acknowledge();
Assert.assertEquals(i, msg.getIntProperty("count").intValue());
}
Assert.assertNull(consumer0.receiveImmediate());
// closing consumer1... it shouldn't redistribute anything as the other nodes don't have such queues
consumer1.close();
Thread.sleep(500); // wait some time giving time to redistribution break something
// (it shouldn't redistribute anything here since there are no queues on the other nodes)
for (int i = 0; i < NUMBER_OF_MESSAGES; i++) {
ClientMessage msg = consumer2.receive(5000);
Assert.assertNotNull(msg);
msg.acknowledge();
Assert.assertEquals(i, msg.getIntProperty("count").intValue());
}
Assert.assertNull(consumer2.receiveImmediate());
Assert.assertNull(consumer0.receiveImmediate());
consumer1 = sess1.createConsumer("queue1");
for (int i = 0; i < NUMBER_OF_MESSAGES; i++) {
ClientMessage msg = consumer1.receive(5000);
Assert.assertNotNull(msg);
msg.acknowledge();
Assert.assertEquals(i, msg.getIntProperty("count").intValue());
}
Assert.assertNull(consumer0.receiveImmediate());
Assert.assertNull(consumer1.receiveImmediate());
Assert.assertNull(consumer2.receiveImmediate());
MessageRedistributionTest.log.info("Test done");
}
@Test
public void testRedistributionWhenConsumerIsClosedNotConsumersOnAllNodes() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, false);
createQueue(1, "queues.testaddress", "queue0", null, false);
createQueue(2, "queues.testaddress", "queue0", null, false);
addConsumer(1, 1, "queue0", null);
addConsumer(2, 2, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 0, true);
waitForBindings(1, "queues.testaddress", 1, 1, true);
waitForBindings(2, "queues.testaddress", 1, 1, true);
waitForBindings(0, "queues.testaddress", 2, 2, false);
waitForBindings(1, "queues.testaddress", 2, 1, false);
waitForBindings(2, "queues.testaddress", 2, 1, false);
send(0, "queues.testaddress", 20, false, null);
int[] ids1 = getReceivedOrder(1);
getReceivedOrder(2);
removeConsumer(1);
verifyReceiveRoundRobinInSomeOrderWithCounts(false, ids1, 2);
}
@Test
public void testNoRedistributionWhenConsumerIsClosedForwardWhenNoConsumersTrue() throws Exception {
// x
setupCluster(MessageLoadBalancingType.STRICT);
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, false);
createQueue(1, "queues.testaddress", "queue0", null, false);
createQueue(2, "queues.testaddress", "queue0", null, false);
addConsumer(0, 0, "queue0", null);
addConsumer(1, 1, "queue0", null);
addConsumer(2, 2, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 1, true);
waitForBindings(2, "queues.testaddress", 1, 1, true);
waitForBindings(0, "queues.testaddress", 2, 2, false);
waitForBindings(1, "queues.testaddress", 2, 2, false);
waitForBindings(2, "queues.testaddress", 2, 2, false);
send(0, "queues.testaddress", 20, false, null);
removeConsumer(1);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 0, true);
waitForBindings(2, "queues.testaddress", 1, 1, true);
waitForBindings(0, "queues.testaddress", 2, 1, false);
waitForBindings(1, "queues.testaddress", 2, 2, false);
waitForBindings(2, "queues.testaddress", 2, 1, false);
addConsumer(1, 1, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 1, true);
waitForBindings(2, "queues.testaddress", 1, 1, true);
waitForBindings(0, "queues.testaddress", 2, 2, false);
waitForBindings(1, "queues.testaddress", 2, 2, false);
waitForBindings(2, "queues.testaddress", 2, 2, false);
verifyReceiveRoundRobinInSomeOrder(20, 0, 1, 2);
}
@Test
public void testNoRedistributionWhenConsumerIsClosedNoConsumersOnOtherNodes() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, false);
createQueue(1, "queues.testaddress", "queue0", null, false);
createQueue(2, "queues.testaddress", "queue0", null, false);
addConsumer(1, 1, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 0, true);
waitForBindings(1, "queues.testaddress", 1, 1, true);
waitForBindings(2, "queues.testaddress", 1, 0, true);
waitForBindings(0, "queues.testaddress", 2, 1, false);
waitForBindings(1, "queues.testaddress", 2, 0, false);
waitForBindings(2, "queues.testaddress", 2, 1, false);
send(0, "queues.testaddress", 20, false, null);
removeConsumer(1);
waitForBindings(0, "queues.testaddress", 1, 0, true);
waitForBindings(1, "queues.testaddress", 1, 0, true);
waitForBindings(2, "queues.testaddress", 1, 0, true);
waitForBindings(0, "queues.testaddress", 2, 0, false);
waitForBindings(1, "queues.testaddress", 2, 0, false);
waitForBindings(2, "queues.testaddress", 2, 0, false);
addConsumer(1, 1, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 0, true);
waitForBindings(1, "queues.testaddress", 1, 1, true);
waitForBindings(2, "queues.testaddress", 1, 0, true);
waitForBindings(0, "queues.testaddress", 2, 1, false);
waitForBindings(1, "queues.testaddress", 2, 0, false);
waitForBindings(2, "queues.testaddress", 2, 1, false);
verifyReceiveAll(20, 1);
}
@Test
public void testRedistributeWithScheduling() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
AddressSettings setting = new AddressSettings().setRedeliveryDelay(10000);
servers[0].getAddressSettingsRepository().addMatch("queues.testaddress", setting);
servers[0].getAddressSettingsRepository().addMatch("queue0", setting);
servers[1].getAddressSettingsRepository().addMatch("queue0", setting);
servers[1].getAddressSettingsRepository().addMatch("queues.testaddress", setting);
startServers(0);
setupSessionFactory(0, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, false);
ClientSession session0 = sfs[0].createSession(false, false, false);
ClientProducer prod0 = session0.createProducer("queues.testaddress");
for (int i = 0; i < 100; i++) {
ClientMessage msg = session0.createMessage(true);
msg.putIntProperty("key", i);
byte[] bytes = new byte[24];
ByteBuffer bb = ByteBuffer.wrap(bytes);
bb.putLong(i);
msg.putBytesProperty(Message.HDR_BRIDGE_DUPLICATE_ID, bytes);
prod0.send(msg);
session0.commit();
}
session0.close();
session0 = sfs[0].createSession(true, false, false);
ClientConsumer consumer0 = session0.createConsumer("queue0");
session0.start();
ArrayList<Xid> xids = new ArrayList<>();
for (int i = 0; i < 100; i++) {
Xid xid = newXID();
session0.start(xid, XAResource.TMNOFLAGS);
ClientMessage msg = consumer0.receive(5000);
msg.acknowledge();
session0.end(xid, XAResource.TMSUCCESS);
session0.prepare(xid);
xids.add(xid);
}
session0.close();
sfs[0].close();
sfs[0] = null;
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
createQueue(1, "queues.testaddress", "queue0", null, false);
createQueue(2, "queues.testaddress", "queue0", null, false);
ClientSession session1 = sfs[1].createSession(false, false);
session1.start();
ClientConsumer consumer1 = session1.createConsumer("queue0");
waitForBindings(0, "queues.testaddress", 1, 0, true);
waitForBindings(1, "queues.testaddress", 1, 1, true);
waitForBindings(2, "queues.testaddress", 1, 0, true);
waitForBindings(0, "queues.testaddress", 2, 1, false);
waitForBindings(1, "queues.testaddress", 2, 0, false);
waitForBindings(2, "queues.testaddress", 2, 1, false);
session0 = sfs[0].createSession(true, false, false);
for (Xid xid : xids) {
session0.rollback(xid);
}
for (int i = 0; i < 100; i++) {
ClientMessage msg = consumer1.receive(15000);
Assert.assertNotNull(msg);
msg.acknowledge();
}
session1.commit();
}
@Test
public void testRedistributionWhenConsumerIsClosedQueuesWithFilters() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
String filter1 = "giraffe";
String filter2 = "platypus";
createQueue(0, "queues.testaddress", "queue0", filter1, false);
createQueue(1, "queues.testaddress", "queue0", filter2, false);
createQueue(2, "queues.testaddress", "queue0", filter1, false);
addConsumer(0, 0, "queue0", null);
addConsumer(1, 1, "queue0", null);
addConsumer(2, 2, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 1, true);
waitForBindings(2, "queues.testaddress", 1, 1, true);
waitForBindings(0, "queues.testaddress", 2, 2, false);
waitForBindings(1, "queues.testaddress", 2, 2, false);
waitForBindings(2, "queues.testaddress", 2, 2, false);
send(0, "queues.testaddress", 20, false, filter1);
int[] ids0 = getReceivedOrder(0);
getReceivedOrder(1);
getReceivedOrder(2);
removeConsumer(0);
verifyReceiveRoundRobinInSomeOrderWithCounts(false, ids0, 2);
}
@Test
public void testRedistributionWhenConsumerIsClosedConsumersWithFilters() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
String filter1 = "giraffe";
String filter2 = "platypus";
createQueue(0, "queues.testaddress", "queue0", null, false);
createQueue(1, "queues.testaddress", "queue0", null, false);
createQueue(2, "queues.testaddress", "queue0", null, false);
addConsumer(0, 0, "queue0", filter1);
addConsumer(1, 1, "queue0", filter2);
addConsumer(2, 2, "queue0", filter1);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 1, true);
waitForBindings(2, "queues.testaddress", 1, 1, true);
waitForBindings(0, "queues.testaddress", 2, 2, false);
waitForBindings(1, "queues.testaddress", 2, 2, false);
waitForBindings(2, "queues.testaddress", 2, 2, false);
send(0, "queues.testaddress", 20, false, filter1);
int[] ids0 = getReceivedOrder(0);
getReceivedOrder(1);
getReceivedOrder(2);
removeConsumer(0);
verifyReceiveRoundRobinInSomeOrderWithCounts(false, ids0, 2);
}
@Test
public void testRedistributionWhenRemoteConsumerIsAdded() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, false);
createQueue(1, "queues.testaddress", "queue0", null, false);
createQueue(2, "queues.testaddress", "queue0", null, false);
addConsumer(0, 0, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 0, true);
waitForBindings(2, "queues.testaddress", 1, 0, true);
waitForBindings(0, "queues.testaddress", 2, 0, false);
waitForBindings(1, "queues.testaddress", 2, 1, false);
waitForBindings(2, "queues.testaddress", 2, 1, false);
send(0, "queues.testaddress", 20, false, null);
removeConsumer(0);
addConsumer(1, 1, "queue0", null);
verifyReceiveAll(20, 1);
verifyNotReceive(1);
}
@Test
public void testBackAndForth() throws Exception {
for (int i = 0; i < 10; i++) {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
final String ADDRESS = "queues.testaddress";
final String QUEUE = "queue0";
createQueue(0, ADDRESS, QUEUE, null, false);
createQueue(1, ADDRESS, QUEUE, null, false);
createQueue(2, ADDRESS, QUEUE, null, false);
addConsumer(0, 0, QUEUE, null);
waitForBindings(0, ADDRESS, 1, 1, true);
waitForBindings(1, ADDRESS, 1, 0, true);
waitForBindings(2, ADDRESS, 1, 0, true);
waitForBindings(0, ADDRESS, 2, 0, false);
waitForBindings(1, ADDRESS, 2, 1, false);
waitForBindings(2, ADDRESS, 2, 1, false);
send(0, ADDRESS, 20, false, null);
waitForMessages(0, ADDRESS, 20);
removeConsumer(0);
waitForBindings(0, ADDRESS, 1, 0, true);
waitForBindings(1, ADDRESS, 1, 0, true);
waitForBindings(2, ADDRESS, 1, 0, true);
waitForBindings(0, ADDRESS, 2, 0, false);
waitForBindings(1, ADDRESS, 2, 0, false);
waitForBindings(2, ADDRESS, 2, 0, false);
addConsumer(1, 1, QUEUE, null);
waitForBindings(0, ADDRESS, 1, 0, true);
waitForBindings(1, ADDRESS, 1, 1, true);
waitForBindings(2, ADDRESS, 1, 0, true);
waitForMessages(1, ADDRESS, 20);
waitForMessages(0, ADDRESS, 0);
waitForBindings(0, ADDRESS, 2, 1, false);
waitForBindings(1, ADDRESS, 2, 0, false);
waitForBindings(2, ADDRESS, 2, 1, false);
removeConsumer(1);
waitForBindings(0, ADDRESS, 1, 0, true);
waitForBindings(1, ADDRESS, 1, 0, true);
waitForBindings(2, ADDRESS, 1, 0, true);
waitForBindings(0, ADDRESS, 2, 0, false);
waitForBindings(1, ADDRESS, 2, 0, false);
waitForBindings(2, ADDRESS, 2, 0, false);
addConsumer(0, 0, QUEUE, null);
waitForBindings(0, ADDRESS, 1, 1, true);
waitForBindings(1, ADDRESS, 1, 0, true);
waitForBindings(2, ADDRESS, 1, 0, true);
waitForBindings(0, ADDRESS, 2, 0, false);
waitForBindings(1, ADDRESS, 2, 1, false);
waitForBindings(2, ADDRESS, 2, 1, false);
waitForMessages(0, ADDRESS, 20);
verifyReceiveAll(20, 0);
verifyNotReceive(0);
addConsumer(1, 1, QUEUE, null);
verifyNotReceive(1);
removeConsumer(1);
stopServers();
start();
}
}
// https://issues.jboss.org/browse/HORNETQ-1072
@Test
public void testBackAndForth2WithDuplicDetection() throws Exception {
internalTestBackAndForth2(true);
}
@Test
public void testBackAndForth2() throws Exception {
internalTestBackAndForth2(false);
}
public void internalTestBackAndForth2(final boolean useDuplicateDetection) throws Exception {
AtomicInteger duplDetection = null;
if (useDuplicateDetection) {
duplDetection = new AtomicInteger(0);
}
for (int i = 0; i < 10; i++) {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0, 1);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
final String ADDRESS = "queues.testaddress";
final String QUEUE = "queue0";
createQueue(0, ADDRESS, QUEUE, null, false);
createQueue(1, ADDRESS, QUEUE, null, false);
addConsumer(0, 0, QUEUE, null);
waitForBindings(0, ADDRESS, 1, 1, true);
waitForBindings(1, ADDRESS, 1, 0, true);
waitForBindings(0, ADDRESS, 1, 0, false);
waitForBindings(1, ADDRESS, 1, 1, false);
send(1, ADDRESS, 20, false, null, duplDetection);
waitForMessages(0, ADDRESS, 20);
removeConsumer(0);
waitForBindings(0, ADDRESS, 1, 0, true);
waitForBindings(1, ADDRESS, 1, 0, true);
waitForBindings(0, ADDRESS, 1, 0, false);
waitForBindings(1, ADDRESS, 1, 0, false);
addConsumer(1, 1, QUEUE, null);
waitForMessages(1, ADDRESS, 20);
waitForMessages(0, ADDRESS, 0);
waitForBindings(0, ADDRESS, 1, 1, false);
waitForBindings(1, ADDRESS, 1, 0, false);
removeConsumer(1);
addConsumer(0, 0, QUEUE, null);
waitForMessages(1, ADDRESS, 0);
waitForMessages(0, ADDRESS, 20);
removeConsumer(0);
addConsumer(1, 1, QUEUE, null);
waitForMessages(1, ADDRESS, 20);
waitForMessages(0, ADDRESS, 0);
verifyReceiveAll(20, 1);
stopServers();
start();
}
}
@Test
public void testRedistributionToQueuesWhereNotAllMessagesMatch() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
String filter1 = "giraffe";
String filter2 = "platypus";
createQueue(0, "queues.testaddress", "queue0", null, false);
createQueue(1, "queues.testaddress", "queue0", null, false);
createQueue(2, "queues.testaddress", "queue0", null, false);
addConsumer(0, 0, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 0, true);
waitForBindings(2, "queues.testaddress", 1, 0, true);
waitForBindings(0, "queues.testaddress", 2, 0, false);
waitForBindings(1, "queues.testaddress", 2, 1, false);
waitForBindings(2, "queues.testaddress", 2, 1, false);
sendInRange(0, "queues.testaddress", 0, 10, false, filter1);
sendInRange(0, "queues.testaddress", 10, 20, false, filter2);
removeConsumer(0);
addConsumer(1, 1, "queue0", filter1);
addConsumer(2, 2, "queue0", filter2);
verifyReceiveAllInRange(0, 10, 1);
verifyReceiveAllInRange(10, 20, 2);
}
@Test
public void testDelayedRedistribution() throws Exception {
final long delay = 1000;
setRedistributionDelay(delay);
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, false);
createQueue(1, "queues.testaddress", "queue0", null, false);
createQueue(2, "queues.testaddress", "queue0", null, false);
addConsumer(0, 0, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 0, true);
waitForBindings(2, "queues.testaddress", 1, 0, true);
waitForBindings(0, "queues.testaddress", 2, 0, false);
waitForBindings(1, "queues.testaddress", 2, 1, false);
waitForBindings(2, "queues.testaddress", 2, 1, false);
send(0, "queues.testaddress", 20, false, null);
long start = System.currentTimeMillis();
removeConsumer(0);
addConsumer(1, 1, "queue0", null);
long minReceiveTime = start + delay;
verifyReceiveAllNotBefore(minReceiveTime, 20, 1);
}
@Test
public void testDelayedRedistributionCancelled() throws Exception {
final long delay = 1000;
setRedistributionDelay(delay);
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, false);
createQueue(1, "queues.testaddress", "queue0", null, false);
createQueue(2, "queues.testaddress", "queue0", null, false);
addConsumer(0, 0, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 0, true);
waitForBindings(2, "queues.testaddress", 1, 0, true);
waitForBindings(0, "queues.testaddress", 2, 0, false);
waitForBindings(1, "queues.testaddress", 2, 1, false);
waitForBindings(2, "queues.testaddress", 2, 1, false);
send(0, "queues.testaddress", 20, false, null);
removeConsumer(0);
addConsumer(1, 1, "queue0", null);
Thread.sleep(delay / 2);
// Add it back on the local queue - this should stop any redistributionm
addConsumer(0, 0, "queue0", null);
Thread.sleep(delay);
verifyReceiveAll(20, 0);
}
@Test
public void testRedistributionNumberOfMessagesGreaterThanBatchSize() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0, 1, 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
setupSessionFactory(2, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, false);
createQueue(1, "queues.testaddress", "queue0", null, false);
createQueue(2, "queues.testaddress", "queue0", null, false);
addConsumer(0, 0, "queue0", null);
waitForBindings(0, "queues.testaddress", 1, 1, true);
waitForBindings(1, "queues.testaddress", 1, 0, true);
waitForBindings(2, "queues.testaddress", 1, 0, true);
waitForBindings(0, "queues.testaddress", 2, 0, false);
waitForBindings(1, "queues.testaddress", 2, 1, false);
waitForBindings(2, "queues.testaddress", 2, 1, false);
send(0, "queues.testaddress", QueueImpl.REDISTRIBUTOR_BATCH_SIZE * 2, false, null);
removeConsumer(0);
addConsumer(1, 1, "queue0", null);
verifyReceiveAll(QueueImpl.REDISTRIBUTOR_BATCH_SIZE * 2, 1);
}
/*
* Start one node with no consumers and send some messages
* Start another node add a consumer and verify all messages are redistribute
* https://jira.jboss.org/jira/browse/HORNETQ-359
*/
@Test
public void testRedistributionWhenNewNodeIsAddedWithConsumer() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
startServers(0);
setupSessionFactory(0, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, false);
waitForBindings(0, "queues.testaddress", 1, 0, true);
send(0, "queues.testaddress", 20, false, null);
// Now bring up node 1
startServers(1);
setupSessionFactory(1, isNetty());
createQueue(1, "queues.testaddress", "queue0", null, false);
waitForBindings(1, "queues.testaddress", 1, 0, true);
waitForBindings(0, "queues.testaddress", 1, 0, false);
addConsumer(0, 1, "queue0", null);
verifyReceiveAll(20, 0);
verifyNotReceive(0);
}
@Test
public void testRedistributionWithPagingOnTarget() throws Exception {
setupCluster(MessageLoadBalancingType.ON_DEMAND);
AddressSettings as = new AddressSettings().setAddressFullMessagePolicy(AddressFullMessagePolicy.PAGE).setPageSizeBytes(10000).setMaxSizeBytes(20000);
getServer(0).getAddressSettingsRepository().addMatch("queues.*", as);
getServer(1).getAddressSettingsRepository().addMatch("queues.*", as);
getServer(2).getAddressSettingsRepository().addMatch("queues.*", as);
startServers(0);
startServers(1);
waitForTopology(getServer(0), 2);
waitForTopology(getServer(1), 2);
setupSessionFactory(0, isNetty());
setupSessionFactory(1, isNetty());
createQueue(0, "queues.testaddress", "queue0", null, true);
createQueue(1, "queues.testaddress", "queue0", null, true);
waitForBindings(1, "queues.testaddress", 1, 0, true);
waitForBindings(0, "queues.testaddress", 1, 0, false);
getServer(0).getPagingManager().getPageStore(new SimpleString("queues.testaddress")).startPaging();
ClientSession session0 = sfs[0].createSession(true, true, 0);
ClientProducer producer0 = session0.createProducer("queues.testaddress");
ClientConsumer consumer0 = session0.createConsumer("queue0");
session0.start();
ClientSession session1 = sfs[1].createSession(true, true, 0);
ClientConsumer consumer1 = session1.createConsumer("queue0");
session1.start();
for (int i = 0; i < 10; i++) {
ClientMessage msg = session0.createMessage(true);
msg.putIntProperty("i", i);
// send two identical messages so they are routed on the cluster
producer0.send(msg);
producer0.send(msg);
msg = consumer0.receive(5000);
Assert.assertNotNull(msg);
Assert.assertEquals(i, msg.getIntProperty("i").intValue());
// msg.acknowledge(); // -- do not ack message on consumer0, to make sure the messages will be paged
msg = consumer1.receive(5000);
Assert.assertNotNull(msg);
Assert.assertEquals(i, msg.getIntProperty("i").intValue());
msg.acknowledge();
}
session0.close();
session1.close();
}
protected void setupCluster(final MessageLoadBalancingType messageLoadBalancingType) throws Exception {
setupClusterConnection("cluster0", "queues", messageLoadBalancingType, 1, isNetty(), 0, 1, 2);
setupClusterConnection("cluster1", "queues", messageLoadBalancingType, 1, isNetty(), 1, 0, 2);
setupClusterConnection("cluster2", "queues", messageLoadBalancingType, 1, isNetty(), 2, 0, 1);
}
protected void setRedistributionDelay(final long delay) {
AddressSettings as = new AddressSettings().setRedistributionDelay(delay);
getServer(0).getAddressSettingsRepository().addMatch("queues.*", as);
getServer(1).getAddressSettingsRepository().addMatch("queues.*", as);
getServer(2).getAddressSettingsRepository().addMatch("queues.*", as);
}
protected void setupServers() throws Exception {
setupServer(0, isFileStorage(), isNetty());
setupServer(1, isFileStorage(), isNetty());
setupServer(2, isFileStorage(), isNetty());
}
protected void stopServers() throws Exception {
closeAllConsumers();
closeAllSessionFactories();
closeAllServerLocatorsFactories();
stopServers(0, 1, 2);
clearServer(0, 1, 2);
}
}