From ad04d52f1d478d8fd96824a90ed7e1b9c2710ac0 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Fri, 29 Dec 2006 18:37:34 +0000 Subject: QPID-232 Created a simple module and added the topic test git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@491072 13f79535-47bb-0310-9956-ffa450edef68 --- .../config/AMQConnectionFactoryInitialiser.java | 35 +++ .../org/apache/qpid/config/AbstractConfig.java | 69 ++++++ .../qpid/config/ConnectionFactoryInitialiser.java | 29 +++ .../java/org/apache/qpid/config/Connector.java | 40 ++++ .../org/apache/qpid/config/ConnectorConfig.java | 28 +++ .../config/JBossConnectionFactoryInitialiser.java | 111 ++++++++++ .../main/java/org/apache/qpid/topic/Config.java | 243 +++++++++++++++++++++ .../main/java/org/apache/qpid/topic/Listener.java | 141 ++++++++++++ .../java/org/apache/qpid/topic/MessageFactory.java | 153 +++++++++++++ .../main/java/org/apache/qpid/topic/Publisher.java | 175 +++++++++++++++ 10 files changed, 1024 insertions(+) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/Connector.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java new file mode 100644 index 0000000000..cac0064785 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java @@ -0,0 +1,35 @@ +/* + * + * 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.qpid.config; + +import org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.config.ConnectionFactoryInitialiser; +import org.apache.qpid.config.ConnectorConfig; + +import javax.jms.ConnectionFactory; + +class AMQConnectionFactoryInitialiser implements ConnectionFactoryInitialiser +{ + public ConnectionFactory getFactory(ConnectorConfig config) + { + return new AMQConnectionFactory(config.getHost(), config.getPort(), "/test_path"); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java new file mode 100644 index 0000000000..04381d66a0 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java @@ -0,0 +1,69 @@ +/* + * + * 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.qpid.config; + +public abstract class AbstractConfig +{ + public boolean setOptions(String[] argv) + { + try + { + for(int i = 0; i < argv.length - 1; i += 2) + { + String key = argv[i]; + String value = argv[i+1]; + setOption(key, value); + } + return true; + } + catch(Exception e) + { + System.out.println(e.getMessage()); + } + return false; + } + + protected int parseInt(String msg, String i) + { + try + { + return Integer.parseInt(i); + } + catch(NumberFormatException e) + { + throw new RuntimeException(msg + ": " + i); + } + } + + protected long parseLong(String msg, String i) + { + try + { + return Long.parseLong(i); + } + catch(NumberFormatException e) + { + throw new RuntimeException(msg + ": " + i); + } + } + + public abstract void setOption(String key, String value); +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java new file mode 100644 index 0000000000..a9984eb09a --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java @@ -0,0 +1,29 @@ +/* + * + * 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.qpid.config; + +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; + +public interface ConnectionFactoryInitialiser +{ + public ConnectionFactory getFactory(ConnectorConfig config) throws JMSException; +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/Connector.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/Connector.java new file mode 100644 index 0000000000..ff2377f087 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/Connector.java @@ -0,0 +1,40 @@ +/* + * + * 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.qpid.config; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; + +public class Connector +{ + public Connection createConnection(ConnectorConfig config) throws Exception + { + return getConnectionFactory(config).createConnection(); + } + + ConnectionFactory getConnectionFactory(ConnectorConfig config) throws Exception + { + String factory = config.getFactory(); + if(factory == null) factory = AMQConnectionFactoryInitialiser.class.getName(); + System.out.println("Using " + factory); + return ((ConnectionFactoryInitialiser) Class.forName(factory).newInstance()).getFactory(config); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java new file mode 100644 index 0000000000..b120ed3f12 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java @@ -0,0 +1,28 @@ +/* + * + * 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.qpid.config; + +public interface ConnectorConfig +{ + public String getHost(); + public int getPort(); + public String getFactory(); +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java new file mode 100644 index 0000000000..44285efd96 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java @@ -0,0 +1,111 @@ +/* + * + * 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.qpid.config; + +import org.apache.qpid.config.ConnectionFactoryInitialiser; +import org.apache.qpid.config.ConnectorConfig; + +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.MBeanException; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.naming.NameNotFoundException; +import java.util.Hashtable; + +public class JBossConnectionFactoryInitialiser implements ConnectionFactoryInitialiser +{ + public ConnectionFactory getFactory(ConnectorConfig config) throws JMSException + { + ConnectionFactory cf = null; + InitialContext ic = null; + Hashtable ht = new Hashtable(); + ht.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); + String jbossHost = System.getProperty("jboss.host", "eqd-lxamq01"); + String jbossPort = System.getProperty("jboss.port", "1099"); + ht.put(InitialContext.PROVIDER_URL, "jnp://" + jbossHost + ":" + jbossPort); + ht.put(InitialContext.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); + + try + { + ic = new InitialContext(ht); + if (!doesDestinationExist("topictest.messages", ic)) + { + deployTopic("topictest.messages", ic); + } + if (!doesDestinationExist("topictest.control", ic)) + { + deployTopic("topictest.control", ic); + } + + cf = (ConnectionFactory) ic.lookup("/ConnectionFactory"); + return cf; + } + catch (NamingException e) + { + throw new JMSException("Unable to lookup object: " + e); + } + catch (Exception e) + { + throw new JMSException("Error creating topic: " + e); + } + } + + private boolean doesDestinationExist(String name, InitialContext ic) throws Exception + { + try + { + ic.lookup("/" + name); + } + catch (NameNotFoundException e) + { + return false; + } + return true; + } + + private void deployTopic(String name, InitialContext ic) throws Exception + { + MBeanServerConnection mBeanServer = lookupMBeanServerProxy(ic); + + ObjectName serverObjectName = new ObjectName("jboss.messaging:service=ServerPeer"); + + String jndiName = "/" + name; + try + { + mBeanServer.invoke(serverObjectName, "createTopic", + new Object[]{name, jndiName}, + new String[]{"java.lang.String", "java.lang.String"}); + } + catch (MBeanException e) + { + System.err.println("Error: " + e); + System.err.println("Cause: " + e.getCause()); + } + } + + private MBeanServerConnection lookupMBeanServerProxy(InitialContext ic) throws NamingException + { + return (MBeanServerConnection) ic.lookup("jmx/invoker/RMIAdaptor"); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java new file mode 100644 index 0000000000..bb740f9094 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java @@ -0,0 +1,243 @@ +/* + * + * 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.qpid.topic; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.config.ConnectorConfig; +import org.apache.qpid.config.ConnectionFactoryInitialiser; +import org.apache.qpid.config.Connector; +import org.apache.qpid.config.AbstractConfig; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; + +class Config extends AbstractConfig implements ConnectorConfig +{ + + private String host = "localhost"; + private int port = 5672; + private String factory = null; + + private int payload = 256; + private int messages = 1000; + private int clients = 1; + private int batch = 1; + private long delay = 1; + private int warmup; + private int ackMode= AMQSession.NO_ACKNOWLEDGE; + private String clientId; + private String subscriptionId; + private boolean persistent; + + public Config() + { + } + + int getAckMode() + { + return ackMode; + } + + void setPayload(int payload) + { + this.payload = payload; + } + + int getPayload() + { + return payload; + } + + void setClients(int clients) + { + this.clients = clients; + } + + int getClients() + { + return clients; + } + + void setMessages(int messages) + { + this.messages = messages; + } + + int getMessages() + { + return messages; + } + + public String getHost() + { + return host; + } + + public void setHost(String host) + { + this.host = host; + } + + public int getPort() + { + return port; + } + + public String getFactory() + { + return factory; + } + + public void setPort(int port) + { + this.port = port; + } + + int getBatch() + { + return batch; + } + + void setBatch(int batch) + { + this.batch = batch; + } + + int getWarmup() + { + return warmup; + } + + void setWarmup(int warmup) + { + this.warmup = warmup; + } + + public long getDelay() + { + return delay; + } + + public void setDelay(long delay) + { + this.delay = delay; + } + + String getClientId() + { + return clientId; + } + + String getSubscriptionId() + { + return subscriptionId; + } + + boolean usePersistentMessages() + { + return persistent; + } + + public void setOption(String key, String value) + { + if("-host".equalsIgnoreCase(key)) + { + setHost(value); + } + else if("-port".equalsIgnoreCase(key)) + { + try + { + setPort(Integer.parseInt(value)); + } + catch(NumberFormatException e) + { + throw new RuntimeException("Bad port number: " + value); + } + } + else if("-payload".equalsIgnoreCase(key)) + { + setPayload(parseInt("Bad payload size", value)); + } + else if("-messages".equalsIgnoreCase(key)) + { + setMessages(parseInt("Bad message count", value)); + } + else if("-clients".equalsIgnoreCase(key)) + { + setClients(parseInt("Bad client count", value)); + } + else if("-batch".equalsIgnoreCase(key)) + { + setBatch(parseInt("Bad batch count", value)); + } + else if("-delay".equalsIgnoreCase(key)) + { + setDelay(parseLong("Bad batch delay", value)); + } + else if("-warmup".equalsIgnoreCase(key)) + { + setWarmup(parseInt("Bad warmup count", value)); + } + else if("-ack".equalsIgnoreCase(key)) + { + ackMode = parseInt("Bad ack mode", value); + } + else if("-factory".equalsIgnoreCase(key)) + { + factory = value; + } + else if("-clientId".equalsIgnoreCase(key)) + { + clientId = value; + } + else if("-subscriptionId".equalsIgnoreCase(key)) + { + subscriptionId = value; + } + else if("-persistent".equalsIgnoreCase(key)) + { + persistent = "true".equalsIgnoreCase(value); + } + else + { + System.out.println("Ignoring unrecognised option: " + key); + } + } + + static String getAckModeDescription(int ackMode) + { + switch(ackMode) + { + case AMQSession.NO_ACKNOWLEDGE: return "NO_ACKNOWLEDGE"; + case AMQSession.AUTO_ACKNOWLEDGE: return "AUTO_ACKNOWLEDGE"; + case AMQSession.CLIENT_ACKNOWLEDGE: return "CLIENT_ACKNOWLEDGE"; + case AMQSession.DUPS_OK_ACKNOWLEDGE: return "DUPS_OK_ACKNOWELDGE"; + case AMQSession.PRE_ACKNOWLEDGE: return "PRE_ACKNOWLEDGE"; + } + return "AckMode=" + ackMode; + } + + public Connection createConnection() throws Exception + { + return new Connector().createConnection(this); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java new file mode 100644 index 0000000000..47c608cfe4 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java @@ -0,0 +1,141 @@ +/* + * + * 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.qpid.topic; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +public class Listener implements MessageListener +{ + private final Connection _connection; + private final MessageProducer _controller; + private final javax.jms.Session _session; + private final MessageFactory _factory; + private boolean init; + private int count; + private long start; + + Listener(Connection connection, int ackMode) throws Exception + { + this(connection, ackMode, null); + } + + Listener(Connection connection, int ackMode, String name) throws Exception + { + _connection = connection; + _session = connection.createSession(false, ackMode); + _factory = new MessageFactory(_session); + + //register for events + if(name == null) + { + _factory.createTopicConsumer().setMessageListener(this); + } + else + { + _factory.createDurableTopicConsumer(name).setMessageListener(this); + } + + _connection.start(); + + _controller = _factory.createControlPublisher(); + System.out.println("Waiting for messages " + + Config.getAckModeDescription(ackMode) + + (name == null ? "" : " (subscribed with name " + name + " and client id " + connection.getClientID() + ")") + + "..."); + + } + + private void shutdown() + { + try + { + _session.close(); + _connection.stop(); + _connection.close(); + } + catch(Exception e) + { + e.printStackTrace(System.out); + } + } + + private void report() + { + try + { + String msg = getReport(); + _controller.send(_factory.createReportResponseMessage(msg)); + System.out.println("Sent report: " + msg); + } + catch(Exception e) + { + e.printStackTrace(System.out); + } + } + + private String getReport() + { + long time = (System.currentTimeMillis() - start); + return "Received " + count + " in " + time + "ms"; + } + + public void onMessage(Message message) + { + if(!init) + { + start = System.currentTimeMillis(); + count = 0; + init = true; + } + + if(_factory.isShutdown(message)) + { + shutdown(); + } + else if(_factory.isReport(message)) + { + //send a report: + report(); + init = false; + } + else if (++count % 100 == 0) + { + System.out.println("Received " + count + " messages."); + } + } + + public static void main(String[] argv) throws Exception + { + Config config = new Config(); + config.setOptions(argv); + + Connection con = config.createConnection(); + if(config.getClientId() != null) + { + con.setClientID(config.getClientId()); + } + new Listener(con, config.getAckMode(), config.getSubscriptionId()); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java new file mode 100644 index 0000000000..1520f18408 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java @@ -0,0 +1,153 @@ +/* + * + * 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.qpid.topic; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; + +import javax.jms.*; + +/** + */ +class MessageFactory +{ + private static final char[] DATA = "abcdefghijklmnopqrstuvwxyz".toCharArray(); + + private final Session _session; + private final Topic _topic; + private final Topic _control; + private final byte[] _payload; + + + MessageFactory(Session session) throws JMSException + { + this(session, 256); + } + + MessageFactory(Session session, int size) throws JMSException + { + _session = session; + if(session instanceof AMQSession) + { + _topic = new AMQTopic("topictest.messages"); + _control = new AMQTopic("topictest.control"); + } + else + { + _topic = session.createTopic("topictest.messages"); + _control = session.createTopic("topictest.control"); + } + _payload = new byte[size]; + + for(int i = 0; i < size; i++) + { + _payload[i] = (byte) DATA[i % DATA.length]; + } + } + + Topic getTopic() + { + return _topic; + } + + Message createEventMessage() throws JMSException + { + BytesMessage msg = _session.createBytesMessage(); + msg.writeBytes(_payload); + return msg; + } + + Message createShutdownMessage() throws JMSException + { + return _session.createTextMessage("SHUTDOWN"); + } + + Message createReportRequestMessage() throws JMSException + { + return _session.createTextMessage("REPORT"); + } + + Message createReportResponseMessage(String msg) throws JMSException + { + return _session.createTextMessage(msg); + } + + boolean isShutdown(Message m) + { + return checkText(m, "SHUTDOWN"); + } + + boolean isReport(Message m) + { + return checkText(m, "REPORT"); + } + + Object getReport(Message m) + { + try + { + return ((TextMessage) m).getText(); + } + catch (JMSException e) + { + e.printStackTrace(System.out); + return e.toString(); + } + } + + MessageConsumer createTopicConsumer() throws Exception + { + return _session.createConsumer(_topic); + } + + MessageConsumer createDurableTopicConsumer(String name) throws Exception + { + return _session.createDurableSubscriber(_topic, name); + } + + MessageConsumer createControlConsumer() throws Exception + { + return _session.createConsumer(_control); + } + + MessageProducer createTopicPublisher() throws Exception + { + return _session.createProducer(_topic); + } + + MessageProducer createControlPublisher() throws Exception + { + return _session.createProducer(_control); + } + + private static boolean checkText(Message m, String s) + { + try + { + return m instanceof TextMessage && ((TextMessage) m).getText().equals(s); + } + catch (JMSException e) + { + e.printStackTrace(System.out); + return false; + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java new file mode 100644 index 0000000000..d788029ee9 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java @@ -0,0 +1,175 @@ +/* + * + * 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.qpid.topic; + +import javax.jms.*; + +public class Publisher implements MessageListener +{ + private final Object _lock = new Object(); + private final Connection _connection; + private final Session _session; + private final MessageFactory _factory; + private final MessageProducer _publisher; + private int _count; + + Publisher(Connection connection, int size, int ackMode, boolean persistent) throws Exception + { + _connection = connection; + _session = _connection.createSession(false, ackMode); + _factory = new MessageFactory(_session, size); + _publisher = _factory.createTopicPublisher(); + _publisher.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + System.out.println("Publishing " + (persistent ? "persistent" : "non-persistent") + " messages of " + size + " bytes, " + Config.getAckModeDescription(ackMode) + "."); + } + + private void test(Config config) throws Exception + { + test(config.getBatch(), config.getDelay(), config.getMessages(), config.getClients(), config.getWarmup()); + } + + private void test(int batches, long delay, int msgCount, int consumerCount, int warmup) throws Exception + { + _factory.createControlConsumer().setMessageListener(this); + _connection.start(); + + if(warmup > 0) + { + System.out.println("Runing warmup (" + warmup + " msgs)"); + long time = batch(warmup, consumerCount); + System.out.println("Warmup completed in " + time + "ms"); + } + + long[] times = new long[batches]; + for(int i = 0; i < batches; i++) + { + if(i > 0) Thread.sleep(delay*1000); + times[i] = batch(msgCount, consumerCount); + System.out.println("Batch " + (i+1) + " of " + batches + " completed in " + times[i] + " ms."); + } + + long min = min(times); + long max = max(times); + System.out.println("min: " + min + ", max: " + max + " avg: " + avg(times, min, max)); + + //request shutdown + _publisher.send(_factory.createShutdownMessage()); + + _connection.stop(); + _connection.close(); + } + + private long batch(int msgCount, int consumerCount) throws Exception + { + _count = consumerCount; + long start = System.currentTimeMillis(); + publish(msgCount); + waitForCompletion(consumerCount); + return System.currentTimeMillis() - start; + } + + private void publish(int count) throws Exception + { + + //send events + for (int i = 0; i < count; i++) + { + _publisher.send(_factory.createEventMessage()); + if ((i + 1) % 100 == 0) + { + System.out.println("Sent " + (i + 1) + " messages"); + } + } + + //request report + _publisher.send(_factory.createReportRequestMessage()); + } + + private void waitForCompletion(int consumers) throws Exception + { + System.out.println("Waiting for completion..."); + synchronized (_lock) + { + while (_count > 0) + { + _lock.wait(); + } + } + } + + + public void onMessage(Message message) + { + System.out.println("Received report " + _factory.getReport(message) + " " + --_count + " remaining"); + if (_count == 0) + { + synchronized (_lock) + { + _lock.notify(); + } + } + } + + static long min(long[] times) + { + long min = times.length > 0 ? times[0] : 0; + for(int i = 0; i < times.length; i++) + { + min = Math.min(min, times[i]); + } + return min; + } + + static long max(long[] times) + { + long max = times.length > 0 ? times[0] : 0; + for(int i = 0; i < times.length; i++) + { + max = Math.max(max, times[i]); + } + return max; + } + + static long avg(long[] times, long min, long max) + { + long sum = 0; + for(int i = 0; i < times.length; i++) + { + sum += times[i]; + } + sum -= min; + sum -= max; + + return (sum / (times.length - 2)); + } + + public static void main(String[] argv) throws Exception + { + Config config = new Config(); + config.setOptions(argv); + + Connection con = config.createConnection(); + int size = config.getPayload(); + int ackMode = config.getAckMode(); + boolean persistent = config.usePersistentMessages(); + new Publisher(con, size, ackMode, persistent).test(config); + } +} -- cgit v1.2.1 From cdc2cd733b01018fbcfe069c42c0a274c0af085e Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 1 Jan 2007 14:30:31 +0000 Subject: QPID-232 Added the service request/reply test git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@491577 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/requestreply/ServiceProvidingClient.java | 201 ++++++++++++++ .../qpid/requestreply/ServiceRequestingClient.java | 303 +++++++++++++++++++++ 2 files changed, 504 insertions(+) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java new file mode 100644 index 0000000000..ddee643a76 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java @@ -0,0 +1,201 @@ +/* + * + * 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.qpid.requestreply; + +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.jms.Session; +import org.apache.qpid.jms.ConnectionListener; +import org.apache.qpid.AMQException; +import org.apache.qpid.url.URLSyntaxException; + +import javax.jms.*; +import java.net.InetAddress; +import java.net.UnknownHostException; + +public class ServiceProvidingClient +{ + private static final Logger _logger = Logger.getLogger(ServiceProvidingClient.class); + + private MessageProducer _destinationProducer; + + private Destination _responseDest; + + private AMQConnection _connection; + + public ServiceProvidingClient(String brokerDetails, String username, String password, + String clientName, String virtualPath, String serviceName) + throws AMQException, JMSException, URLSyntaxException + { + _connection = new AMQConnection(brokerDetails, username, password, + clientName, virtualPath); + _connection.setConnectionListener(new ConnectionListener() + { + + public void bytesSent(long count) + { + } + + public void bytesReceived(long count) + { + } + + public boolean preFailover(boolean redirect) + { + return true; + } + + public boolean preResubscribe() + { + return true; + } + + public void failoverComplete() + { + _logger.info("App got failover complete callback"); + } + }); + final Session session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + _logger.info("Service (queue) name is '" + serviceName + "'..."); + + AMQQueue destination = new AMQQueue(serviceName); + + MessageConsumer consumer = session.createConsumer(destination, + 100, true, false, null); + + consumer.setMessageListener(new MessageListener() + { + private int _messageCount; + + public void onMessage(Message message) + { + //_logger.info("Got message '" + message + "'"); + + TextMessage tm = (TextMessage) message; + + try + { + Destination responseDest = tm.getJMSReplyTo(); + if (responseDest == null) + { + _logger.info("Producer not created because the response destination is null."); + return; + } + + if (!responseDest.equals(_responseDest)) + { + _responseDest = responseDest; + + _logger.info("About to create a producer"); + _destinationProducer = session.createProducer(responseDest); + _destinationProducer.setDisableMessageTimestamp(true); + _destinationProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + _logger.info("After create a producer"); + } + } + catch (JMSException e) + { + _logger.error("Error creating destination"); + } + _messageCount++; + if (_messageCount % 1000 == 0) + { + _logger.info("Received message total: " + _messageCount); + _logger.info("Sending response to '" + _responseDest + "'"); + } + + try + { + String payload = "This is a response: sing together: 'Mahnah mahnah...'" + tm.getText(); + TextMessage msg = session.createTextMessage(payload); + if (tm.propertyExists("timeSent")) + { + _logger.info("timeSent property set on message"); + _logger.info("timeSent value is: " + tm.getLongProperty("timeSent")); + msg.setStringProperty("timeSent", tm.getStringProperty("timeSent")); + } + _destinationProducer.send(msg); + if (_messageCount % 1000 == 0) + { + _logger.info("Sent response to '" + _responseDest + "'"); + } + } + catch (JMSException e) + { + _logger.error("Error sending message: " + e, e); + } + } + }); + } + + public void run() throws JMSException + { + _connection.start(); + _logger.info("Waiting..."); + } + + public static void main(String[] args) + { + _logger.info("Starting..."); + + if (args.length < 5) + { + System.out.println("Usage: brokerDetails username password virtual-path serviceQueue [selector]"); + System.exit(1); + } + String clientId = null; + try + { + InetAddress address = InetAddress.getLocalHost(); + clientId = address.getHostName() + System.currentTimeMillis(); + } + catch (UnknownHostException e) + { + _logger.error("Error: " + e, e); + } + + try + { + ServiceProvidingClient client = new ServiceProvidingClient(args[0], args[1], args[2], + clientId, args[3], args[4]); + client.run(); + } + catch (JMSException e) + { + _logger.error("Error: " + e, e); + } + catch (AMQException e) + { + _logger.error("Error: " + e, e); + } + catch (URLSyntaxException e) + { + _logger.error("Error: " + e, e); + } + + + + } + +} + diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java new file mode 100644 index 0000000000..b52d06558a --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java @@ -0,0 +1,303 @@ +/* + * + * 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.qpid.requestreply; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.jms.MessageConsumer; +import org.apache.qpid.jms.MessageProducer; +import org.apache.qpid.jms.Session; + +import javax.jms.*; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * A client that behaves as follows: + * + * + */ +public class ServiceRequestingClient implements ExceptionListener +{ + private static final Logger _log = Logger.getLogger(ServiceRequestingClient.class); + + private static final String MESSAGE_DATA_BYTES = "jfd ghljgl hjvhlj cvhvjf ldhfsj lhfdsjf hldsjfk hdslkfj hsdflk "; + + private String MESSAGE_DATA; + + private AMQConnection _connection; + + private Session _session; + + private long _averageLatency; + + private int _messageCount; + + private volatile boolean _completed; + + private AMQDestination _tempDestination; + + private MessageProducer _producer; + + private Object _waiter; + + private static String createMessagePayload(int size) + { + _log.info("Message size set to " + size + " bytes"); + StringBuffer buf = new StringBuffer(size); + int count = 0; + while (count < size + MESSAGE_DATA_BYTES.length()) + { + buf.append(MESSAGE_DATA_BYTES); + count += MESSAGE_DATA_BYTES.length(); + } + if (count < size) + { + buf.append(MESSAGE_DATA_BYTES, 0, size - count); + } + + return buf.toString(); + } + + private class CallbackHandler implements MessageListener + { + private int _expectedMessageCount; + + private int _actualMessageCount; + + private long _startTime; + + public CallbackHandler(int expectedMessageCount, long startTime) + { + _expectedMessageCount = expectedMessageCount; + _startTime = startTime; + } + + public void onMessage(Message m) + { + if (_log.isDebugEnabled()) + { + _log.debug("Message received: " + m); + } + try + { + m.getPropertyNames(); + if (m.propertyExists("timeSent")) + { + long timeSent = Long.parseLong(m.getStringProperty("timeSent")); + long now = System.currentTimeMillis(); + if (_averageLatency == 0) + { + _averageLatency = now - timeSent; + _log.info("Latency " + _averageLatency); + } + else + { + _log.info("Individual latency: " + (now - timeSent)); + _averageLatency = (_averageLatency + (now - timeSent)) / 2; + _log.info("Average latency now: " + _averageLatency); + } + } + } + catch (JMSException e) + { + _log.error("Error getting latency data: " + e, e); + } + _actualMessageCount++; + if (_actualMessageCount % 1000 == 0) + { + _log.info("Received message count: " + _actualMessageCount); + } + + if (_actualMessageCount == _expectedMessageCount) + { + _completed = true; + notifyWaiter(); + long timeTaken = System.currentTimeMillis() - _startTime; + _log.info("Total time taken to receive " + _expectedMessageCount + " messages was " + + timeTaken + "ms, equivalent to " + + (_expectedMessageCount / (timeTaken / 1000.0)) + " messages per second"); + + try + { + _connection.close(); + _log.info("Connection closed"); + } + catch (JMSException e) + { + _log.error("Error closing connection"); + } + } + } + } + + private void notifyWaiter() + { + if (_waiter != null) + { + synchronized (_waiter) + { + _waiter.notify(); + } + } + } + public ServiceRequestingClient(String brokerHosts, String clientID, String username, String password, + String vpath, String commandQueueName, + final int messageCount, final int messageDataLength) throws AMQException, URLSyntaxException + { + _messageCount = messageCount; + MESSAGE_DATA = createMessagePayload(messageDataLength); + try + { + createConnection(brokerHosts, clientID, username, password, vpath); + _session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + _connection.setExceptionListener(this); + + + AMQQueue destination = new AMQQueue(commandQueueName); + _producer = (MessageProducer) _session.createProducer(destination); + _producer.setDisableMessageTimestamp(true); + _producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + _tempDestination = new AMQQueue("TempResponse" + + Long.toString(System.currentTimeMillis()), true); + MessageConsumer messageConsumer = (MessageConsumer) _session.createConsumer(_tempDestination, 100, true, + true, null); + + //Send first message, then wait a bit to allow the provider to get initialised + TextMessage first = _session.createTextMessage(MESSAGE_DATA); + first.setJMSReplyTo(_tempDestination); + _producer.send(first); + try + { + Thread.sleep(1000); + } + catch (InterruptedException ignore) + { + } + + //now start the clock and the test... + final long startTime = System.currentTimeMillis(); + + messageConsumer.setMessageListener(new CallbackHandler(messageCount, startTime)); + } + catch (JMSException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + + /** + * Run the test and notify an object upon receipt of all responses. + * @param waiter the object that will be notified + * @throws JMSException + */ + public void run(Object waiter) throws JMSException + { + _waiter = waiter; + _connection.start(); + for (int i = 1; i < _messageCount; i++) + { + TextMessage msg = _session.createTextMessage(MESSAGE_DATA + i); + msg.setJMSReplyTo(_tempDestination); + if (i % 1000 == 0) + { + long timeNow = System.currentTimeMillis(); + msg.setStringProperty("timeSent", String.valueOf(timeNow)); + } + _producer.send(msg); + } + _log.info("Finished sending " + _messageCount + " messages"); + } + + public boolean isCompleted() + { + return _completed; + } + + private void createConnection(String brokerHosts, String clientID, String username, String password, + String vpath) throws AMQException, URLSyntaxException + { + _connection = new AMQConnection(brokerHosts, username, password, + clientID, vpath); + } + + /** + * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank + * means the server will allocate a name. + */ + public static void main(String[] args) + { + if (args.length < 6) + { + System.err.println( + "Usage: ServiceRequestingClient "); + } + try + { + int messageDataLength = args.length > 6 ? Integer.parseInt(args[6]) : 4096; + + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); + ServiceRequestingClient client = new ServiceRequestingClient(args[0], clientID, args[1], args[2], args[3], + args[4], Integer.parseInt(args[5]), + messageDataLength); + Object waiter = new Object(); + client.run(waiter); + synchronized (waiter) + { + while (!client.isCompleted()) + { + waiter.wait(); + } + } + + } + catch (UnknownHostException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + catch (Exception e) + { + System.err.println("Error in client: " + e); + e.printStackTrace(); + } + } + + /** + * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) + */ + public void onException(JMSException e) + { + System.err.println(e.getMessage()); + e.printStackTrace(System.err); + } +} -- cgit v1.2.1 From bd257f3a8b5e72da0400f678855164b117897879 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 10 Jan 2007 15:47:18 +0000 Subject: QPID-278 Add PerfTests into build and distribution perftests are now built as part of the main build. The resulting jar contains both class and java files. The binary distribution also includes a perftests folder in the bin directory which contains scripts to run the tests. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@494861 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/pingpong/TestPingClient.java | 138 +++++++++++++ .../org/apache/qpid/pingpong/TestPingProducer.java | 223 +++++++++++++++++++++ .../apache/qpid/pingpong/TestPingPublisher.java | 188 +++++++++++++++++ .../apache/qpid/pingpong/TestPingSubscriber.java | 134 +++++++++++++ .../qpid/requestreply/ServiceRequestingClient.java | 6 +- 5 files changed, 687 insertions(+), 2 deletions(-) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingClient.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingProducer.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingPublisher.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingSubscriber.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingClient.java new file mode 100644 index 0000000000..c96f6bd61d --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingClient.java @@ -0,0 +1,138 @@ +/* + * + * 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.qpid.pingpong; + +import org.apache.log4j.Logger; +import org.apache.log4j.Level; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.jms.Session; + +import javax.jms.*; +import java.net.InetAddress; + +public class TestPingClient +{ + private static final Logger _logger = Logger.getLogger(TestPingClient.class); + + private static class TestPingMessageListener implements MessageListener + { + public TestPingMessageListener() + { + } + + long _lastTimestamp = 0L; + long _lastTimestampString = 0L; + + public void onMessage(javax.jms.Message message) + { + if (_logger.isInfoEnabled()) + { + long timestamp = 0L; + long timestampString = 0L; + + try + { + timestamp = message.getLongProperty("timestamp"); + timestampString = Long.parseLong(message.getStringProperty("timestampString")); + + if (timestampString != timestamp) + { + _logger.info("Timetamps differ!:\n" + + "timestamp:" + timestamp + "\n" + + "timestampString:" + timestampString); + } + + } + catch (JMSException jmse) + { + //ignore + } + + long diff = timestamp - _lastTimestamp; + _lastTimestamp = timestamp; + + long stringDiff = timestampString - _lastTimestampString; + + _lastTimestampString = timestampString; + + _logger.info("Ping: T:" + diff + "ms, TS:" + stringDiff); + + // _logger.info(_name + " got message '" + message + "\n"); + } + } + } + + public static void main(String[] args) + { + _logger.setLevel(Level.INFO); + + _logger.info("Starting..."); + + if (args.length < 4) + { + System.out.println("Usage: brokerdetails username password virtual-path [selector] "); + System.exit(1); + } + try + { + InetAddress address = InetAddress.getLocalHost(); + AMQConnection con1 = new AMQConnection(args[0], args[1], args[2], + address.getHostName(), args[3]); + + + _logger.info("Connected with URL:" + con1.toURL()); + + final org.apache.qpid.jms.Session session1 = (org.apache.qpid.jms.Session) + con1.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + String selector = null; + + if (args.length == 5) + { + selector = args[4]; + _logger.info("Message selector is <" + selector + ">..."); + } + else + { + _logger.info("Not using message selector"); + } + + + Queue q = new AMQQueue("ping"); + + MessageConsumer consumer1 = session1.createConsumer(q, + 1, false, false, selector); + + consumer1.setMessageListener(new TestPingMessageListener()); + con1.start(); + } + catch (Throwable t) + { + System.err.println("Fatal error: " + t); + t.printStackTrace(); + } + + System.out.println("Waiting..."); + } +} + diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingProducer.java new file mode 100644 index 0000000000..cb9154d97b --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingProducer.java @@ -0,0 +1,223 @@ +/* + * + * 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.qpid.pingpong; + +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.AMQException; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.qpid.client.AMQNoConsumersException; +import org.apache.qpid.client.BasicMessageProducer; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.jms.MessageProducer; +import org.apache.qpid.jms.Session; + +import javax.jms.*; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * A client that behaves as follows: + *
  • Connects to a queue, whose name is specified as a cmd-line argument
  • + *
  • Creates a temporary queue
  • + *
  • Creates messages containing a property that is the name of the temporary queue
  • + *
  • Fires off a message on the original queue and waits for a response on the temporary queue
  • + *
+ */ +public class TestPingProducer implements ExceptionListener +{ + private static final Logger _log = Logger.getLogger(TestPingProducer.class); + + private AMQConnection _connection; + + + private boolean _publish; + + private long SLEEP_TIME = 250L; + +// private class CallbackHandler implements MessageListener +// { +// +// private int _actualMessageCount; +// +// +// public void onMessage(Message m) +// { +// if (_log.isDebugEnabled()) +// { +// _log.debug("Message received: " + m); +// } +// _actualMessageCount++; +// if (_actualMessageCount % 1000 == 0) +// { +// _log.info("Received message count: " + _actualMessageCount); +// } +// } +// } + + public TestPingProducer(boolean TRANSACTED, String brokerDetails, String clientID, + String virtualpath) throws AMQException, URLSyntaxException + { + try + { + createConnection(brokerDetails, clientID, virtualpath); + + Session session; + + if (TRANSACTED) + { + session = (Session) _connection.createSession(true, Session.SESSION_TRANSACTED); + } + else + { + session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + String queue = "ping"; + AMQQueue destination = new AMQQueue(queue); + MessageProducer producer = (MessageProducer) session.createProducer(destination); + + _connection.setExceptionListener(this); + + _connection.start(); + + while (_publish) + { +/* + TextMessage msg = session.createTextMessage( + "Presented to in conjunction with Mahnah Mahnah and the Snowths: " + ++messageNumber); +*/ + ObjectMessage msg = session.createObjectMessage(); + + msg.setStringProperty("timestampString", Long.toString(System.currentTimeMillis())); + msg.setLongProperty("timestamp", System.currentTimeMillis()); + + ((BasicMessageProducer) producer).send(msg, DeliveryMode.NON_PERSISTENT, true); + _log.info("Message Sent."); + _log.debug(msg); + + + if (TRANSACTED) + { + try + { + session.commit(); + _log.debug("Session Commited."); + } + catch (JMSException e) + { + _log.trace("JMSException on commit:" + e); + try + { + session.rollback(); + _log.debug("Message rolled back."); + } + catch (JMSException jsme) + { + _log.trace("JMSE on rollback:" + jsme); + } + + + if (e.getLinkedException() instanceof AMQNoConsumersException) + { + _log.info("No Consumers on queue:'" + queue + "'"); + continue; + } + } + } + + + if (SLEEP_TIME > 0) + { + try + { + Thread.sleep(SLEEP_TIME); + } + catch (InterruptedException ie) + { + //do nothing + } + } + + + } + + } + catch (JMSException e) + { + _publish = false; + e.printStackTrace(); + } + } + + private void createConnection(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException + { + _publish = true; + _connection = new AMQConnection(brokerDetails, "guest", "guest", + clientID, virtualpath); + _log.info("Connected with URL:" + _connection.toURL()); + } + + /** + * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank + * means the server will allocate a name. + */ + public static void main(String[] args) + { + if (args.length < 2) + { + System.err.println("Usage: TestPingPublisher [transacted]"); + System.exit(0); + } + try + { + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); + new TestPingProducer(args.length == 3, args[0], clientID, args[1]); + } + catch (UnknownHostException e) + { + e.printStackTrace(); + } + catch (AMQException e) + { + System.err.println("Error in client: " + e); + e.printStackTrace(); + } + catch (URLSyntaxException e) + { + System.err.println("Error in connection arguments : " + e); + } + + //System.exit(0); + } + + /** + * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) + */ + public void onException(JMSException e) + { + System.err.println(e.getMessage()); + + _publish = false; + e.printStackTrace(System.err); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingPublisher.java b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingPublisher.java new file mode 100644 index 0000000000..9f66387497 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingPublisher.java @@ -0,0 +1,188 @@ +/* + * + * 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.qpid.pingpong; + +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.AMQException; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.BasicMessageProducer; +import org.apache.qpid.jms.MessageProducer; +import org.apache.qpid.jms.Session; + +import javax.jms.*; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * A client that behaves as follows: + *
  • Connects to a queue, whose name is specified as a cmd-line argument
  • + *
  • Creates a temporary queue
  • + *
  • Creates messages containing a property that is the name of the temporary queue
  • + *
  • Fires off a message on the original queue and waits for a response on the temporary queue
  • + *
+ */ +public class TestPingPublisher implements ExceptionListener +{ + private static final Logger _log = Logger.getLogger(TestPingPublisher.class); + + private AMQConnection _connection; + + private boolean _publish; + + private long SLEEP_TIME = 0L; + +// private class CallbackHandler implements MessageListener +// { +// +// private int _actualMessageCount; +// +// +// public void onMessage(Message m) +// { +// if (_log.isDebugEnabled()) +// { +// _log.debug("Message received: " + m); +// } +// _actualMessageCount++; +// if (_actualMessageCount % 1000 == 0) +// { +// _log.info("Received message count: " + _actualMessageCount); +// } +// } +// } + + public TestPingPublisher(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException + { + try + { + createConnection(brokerDetails, clientID, virtualpath); + + Session session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + //AMQQueue destination = new AMQQueue("ping"); + AMQTopic destination = new AMQTopic("ping"); + MessageProducer producer = (MessageProducer) session.createProducer(destination); + + _connection.setExceptionListener(this); + + _connection.start(); + + int msgCount = 0; + while (_publish) + { +/* + TextMessage msg = session.createTextMessage( + "Presented to in conjunction with Mahnah Mahnah and the Snowths: " + ++messageNumber); +*/ + ObjectMessage msg = session.createObjectMessage(); + + Long time = System.nanoTime(); + msg.setStringProperty("timestampString", Long.toString(time)); + msg.setLongProperty("timestamp", time); + + ((BasicMessageProducer) producer).send(msg, DeliveryMode.PERSISTENT, true); + + _log.info("Message Sent:" + msgCount++); + _log.debug(msg); + + if (msgCount == Integer.MAX_VALUE) + { + _publish = false; + } + + if (SLEEP_TIME > 0) + { + try + { + Thread.sleep(SLEEP_TIME); + } + catch (InterruptedException ie) + { + //do nothing + } + } + + + } + + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + + private void createConnection(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException + { + _publish = true; + _connection = new AMQConnection(brokerDetails, "guest", "guest", + clientID, virtualpath); + + _log.info("Connected with URL:" + _connection.toURL()); + } + + /** + * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank + * means the server will allocate a name. + */ + public static void main(String[] args) + { + if (args.length < 2) + { + System.err.println("Usage: TestPingPublisher "); + System.exit(0); + } + try + { + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); + new TestPingPublisher(args[0], clientID, args[1]); + } + catch (UnknownHostException e) + { + e.printStackTrace(); + } + catch (AMQException e) + { + System.err.println("Error in client: " + e); + e.printStackTrace(); + } + catch (URLSyntaxException e) + { + System.err.println("Error in connection arguments : " + e); + } + + //System.exit(0); + } + + /** + * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) + */ + public void onException(JMSException e) + { + System.err.println(e.getMessage()); + + _publish = false; + e.printStackTrace(System.err); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingSubscriber.java b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingSubscriber.java new file mode 100644 index 0000000000..001f1e3568 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingSubscriber.java @@ -0,0 +1,134 @@ +/* + * + * 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.qpid.pingpong; + +import org.apache.log4j.Logger; +import org.apache.log4j.Level; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.jms.Session; + +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Topic; +import javax.jms.JMSException; +import java.net.InetAddress; + +public class TestPingSubscriber +{ + private static final Logger _logger = Logger.getLogger(TestPingSubscriber.class); + + private static class TestPingMessageListener implements MessageListener + { + public TestPingMessageListener() + { + } + + long _lastTimestamp = 0L; + long _lastTimestampString = 0L; + + public void onMessage(javax.jms.Message message) + { + Long time = System.nanoTime(); + + if (_logger.isInfoEnabled()) + { + long timestampString = 0L; + + try + { + long timestamp = message.getLongProperty("timestamp"); + timestampString = Long.parseLong(message.getStringProperty("timestampString")); + + if (timestampString != timestamp) + { + _logger.info("Timetamps differ!:\n" + + "timestamp:" + timestamp + "\n" + + "timestampString:" + timestampString); + } + + } + catch (JMSException jmse) + { + // ignore + } + + + long stringDiff = time - timestampString; + + _logger.info("Ping: TS:" + stringDiff / 1000 + "us"); + + // _logger.info(_name + " got message '" + message + "\n"); + } + } + } + + public static void main(String[] args) + { + _logger.info("Starting..."); + + if (args.length < 4) + { + System.out.println("Usage: brokerdetails username password virtual-path [selector] "); + System.exit(1); + } + try + { + InetAddress address = InetAddress.getLocalHost(); + AMQConnection con1 = new AMQConnection(args[0], args[1], args[2], + address.getHostName(), args[3]); + + _logger.info("Connected with URL:" + con1.toURL()); + + final org.apache.qpid.jms.Session session1 = (org.apache.qpid.jms.Session) + con1.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + String selector = null; + + if (args.length == 5) + { + selector = args[4]; + _logger.info("Message selector is <" + selector + ">..."); + } + else + { + _logger.info("Not using message selector "); + } + + Topic t = new AMQTopic("ping"); + + MessageConsumer consumer1 = session1.createConsumer(t, + 1, false, false, selector); + + consumer1.setMessageListener(new TestPingMessageListener()); + con1.start(); + } + catch (Throwable t) + { + System.err.println("Fatal error: " + t); + t.printStackTrace(); + } + + System.out.println("Waiting..."); + } +} + diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java index b52d06558a..93e2d4685b 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java @@ -41,7 +41,6 @@ import java.net.UnknownHostException; *
  • Creates messages containing a property that is the name of the temporary queue
  • *
  • Fires off a message on the original queue and waits for a response on the temporary queue
  • * - * */ public class ServiceRequestingClient implements ExceptionListener { @@ -167,6 +166,7 @@ public class ServiceRequestingClient implements ExceptionListener } } } + public ServiceRequestingClient(String brokerHosts, String clientID, String username, String password, String vpath, String commandQueueName, final int messageCount, final int messageDataLength) throws AMQException, URLSyntaxException @@ -217,6 +217,7 @@ public class ServiceRequestingClient implements ExceptionListener /** * Run the test and notify an object upon receipt of all responses. + * * @param waiter the object that will be notified * @throws JMSException */ @@ -260,6 +261,7 @@ public class ServiceRequestingClient implements ExceptionListener { System.err.println( "Usage: ServiceRequestingClient "); + System.exit(1); } try { @@ -292,7 +294,7 @@ public class ServiceRequestingClient implements ExceptionListener } } - /** + /** * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) */ public void onException(JMSException e) -- cgit v1.2.1 From 92cbcc95df7ea2ae2aba2ab94730e027462bf15d Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Wed, 10 Jan 2007 17:41:11 +0000 Subject: amended ping tests to allow variation of message sizes git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@494904 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/message/TestMessageFactory.java | 83 ++++++++++++++++++++++ .../org/apache/qpid/pingpong/TestPingProducer.java | 30 ++++++-- .../apache/qpid/pingpong/TestPingPublisher.java | 25 ++++--- 3 files changed, 125 insertions(+), 13 deletions(-) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java new file mode 100644 index 0000000000..dc2bf39a9b --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java @@ -0,0 +1,83 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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.qpid.client.message; + +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.SimpleByteBufferAllocator; + +import javax.jms.JMSException; +import javax.jms.Session; +import javax.jms.ObjectMessage; +import javax.jms.StreamMessage; +import javax.jms.BytesMessage; +import javax.jms.TextMessage; + +public class TestMessageFactory +{ + private static final String MESSAGE_DATA_BYTES = "-message payload-message paylaod-message payload-message paylaod"; + + public static TextMessage newTextMessage(Session session, int size) throws JMSException + { + return session.createTextMessage(createMessagePayload(size)); + } + + public static JMSTextMessage newJMSTextMessage(int size, String encoding) throws JMSException + { + ByteBuffer byteBuffer = (new SimpleByteBufferAllocator()).allocate(size, true); + JMSTextMessage message = new JMSTextMessage(byteBuffer, encoding); + message.clearBody(); + message.setText(createMessagePayload(size)); + return message; + } + + public static BytesMessage newBytesMessage(Session session, int size) throws JMSException + { + BytesMessage message = session.createBytesMessage(); + message.writeUTF(createMessagePayload(size)); + return message; + } + + public static StreamMessage newStreamMessage(Session session, int size) throws JMSException + { + StreamMessage message = session.createStreamMessage(); + message.writeString(createMessagePayload(size)); + return message; + } + + public static ObjectMessage newObjectMessage(Session session, int size) throws JMSException + { + return session.createObjectMessage(createMessagePayload(size)); + } + + public static String createMessagePayload(int size) + { + StringBuffer buf = new StringBuffer(size); + int count = 0; + while (count < size) + { + buf.append(MESSAGE_DATA_BYTES); + count += MESSAGE_DATA_BYTES.length(); + } + if (count < size) + { + buf.append(MESSAGE_DATA_BYTES, 0, size - count); + } + + return buf.toString(); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingProducer.java index cb9154d97b..bb9e17615e 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingProducer.java @@ -27,6 +27,7 @@ import org.apache.qpid.url.URLSyntaxException; import org.apache.qpid.client.AMQNoConsumersException; import org.apache.qpid.client.BasicMessageProducer; import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; @@ -48,7 +49,7 @@ public class TestPingProducer implements ExceptionListener private AMQConnection _connection; - + private static int _messageSize = 0; private boolean _publish; private long SLEEP_TIME = 250L; @@ -105,8 +106,16 @@ public class TestPingProducer implements ExceptionListener TextMessage msg = session.createTextMessage( "Presented to in conjunction with Mahnah Mahnah and the Snowths: " + ++messageNumber); */ - ObjectMessage msg = session.createObjectMessage(); - + ObjectMessage msg = null; + if (_messageSize != 0) + { + msg = TestMessageFactory.newObjectMessage(session, _messageSize); + } + else + { + msg = session.createObjectMessage(); + } + msg.setStringProperty("timestampString", Long.toString(System.currentTimeMillis())); msg.setLongProperty("timestamp", System.currentTimeMillis()); @@ -184,14 +193,25 @@ public class TestPingProducer implements ExceptionListener { if (args.length < 2) { - System.err.println("Usage: TestPingPublisher [transacted]"); + System.err.println("Usage: TestPingPublisher [transacted] [message size in bytes]"); System.exit(0); } try { InetAddress address = InetAddress.getLocalHost(); String clientID = address.getHostName() + System.currentTimeMillis(); - new TestPingProducer(args.length == 3, args[0], clientID, args[1]); + boolean transacted = false; + if (args.length == 3 ) + { + transacted = Boolean.parseBoolean(args[2]); + } + else if (args.length > 3 ) + { + transacted = Boolean.parseBoolean(args[2]); + _messageSize = Integer.parseInt(args[3]); + } + + new TestPingProducer(transacted, args[0], clientID, args[1]); } catch (UnknownHostException e) { diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingPublisher.java b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingPublisher.java index 9f66387497..3b2dcc4d36 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingPublisher.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingPublisher.java @@ -26,6 +26,7 @@ import org.apache.qpid.AMQException; import org.apache.qpid.url.URLSyntaxException; import org.apache.qpid.client.AMQTopic; import org.apache.qpid.client.BasicMessageProducer; +import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; @@ -48,7 +49,7 @@ public class TestPingPublisher implements ExceptionListener private AMQConnection _connection; private boolean _publish; - + private static int _messageSize = 0; private long SLEEP_TIME = 0L; // private class CallbackHandler implements MessageListener @@ -94,7 +95,15 @@ public class TestPingPublisher implements ExceptionListener TextMessage msg = session.createTextMessage( "Presented to in conjunction with Mahnah Mahnah and the Snowths: " + ++messageNumber); */ - ObjectMessage msg = session.createObjectMessage(); + ObjectMessage msg = null; + if (_messageSize != 0) + { + msg = TestMessageFactory.newObjectMessage(session, _messageSize); + } + else + { + msg = session.createObjectMessage(); + } Long time = System.nanoTime(); msg.setStringProperty("timestampString", Long.toString(time)); @@ -121,8 +130,6 @@ public class TestPingPublisher implements ExceptionListener //do nothing } } - - } } @@ -135,9 +142,7 @@ public class TestPingPublisher implements ExceptionListener private void createConnection(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException { _publish = true; - _connection = new AMQConnection(brokerDetails, "guest", "guest", - clientID, virtualpath); - + _connection = new AMQConnection(brokerDetails, "guest", "guest", clientID, virtualpath); _log.info("Connected with URL:" + _connection.toURL()); } @@ -149,13 +154,17 @@ public class TestPingPublisher implements ExceptionListener { if (args.length < 2) { - System.err.println("Usage: TestPingPublisher "); + System.err.println("Usage: TestPingPublisher [message size in bytes]"); System.exit(0); } try { InetAddress address = InetAddress.getLocalHost(); String clientID = address.getHostName() + System.currentTimeMillis(); + if (args.length > 2 ) + { + _messageSize = Integer.parseInt(args[2]); + } new TestPingPublisher(args[0], clientID, args[1]); } catch (UnknownHostException e) -- cgit v1.2.1 From c36a4fd59772a66d8934fa31696d7d2cd9492b10 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 10 Jan 2007 22:44:42 +0000 Subject: QPID-32 : Add option to run tests with persistent messages git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495020 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/requestreply/ServiceProvidingClient.java | 39 +++++++++++++++----- .../qpid/requestreply/ServiceRequestingClient.java | 42 +++++++++++++++++----- 2 files changed, 63 insertions(+), 18 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java index ddee643a76..a261d8e5da 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java @@ -42,10 +42,21 @@ public class ServiceProvidingClient private AMQConnection _connection; + private Session _session; + private Session _producerSession; + + private boolean _isTransactional; + public ServiceProvidingClient(String brokerDetails, String username, String password, - String clientName, String virtualPath, String serviceName) + String clientName, String virtualPath, String serviceName, + String deliveryModeString, String transactedMode) throws AMQException, JMSException, URLSyntaxException { + final int deliveryMode = deliveryModeString.toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT; + _isTransactional = transactedMode.toUpperCase().charAt(0) == 'T' ? true : false; + + _logger.info("Delivery Mode: " + deliveryMode + "\t isTransactional: " + _isTransactional); + _connection = new AMQConnection(brokerDetails, username, password, clientName, virtualPath); _connection.setConnectionListener(new ConnectionListener() @@ -74,13 +85,14 @@ public class ServiceProvidingClient _logger.info("App got failover complete callback"); } }); - final Session session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _session = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE); + _producerSession = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE); _logger.info("Service (queue) name is '" + serviceName + "'..."); AMQQueue destination = new AMQQueue(serviceName); - MessageConsumer consumer = session.createConsumer(destination, + MessageConsumer consumer = _session.createConsumer(destination, 100, true, false, null); consumer.setMessageListener(new MessageListener() @@ -107,9 +119,9 @@ public class ServiceProvidingClient _responseDest = responseDest; _logger.info("About to create a producer"); - _destinationProducer = session.createProducer(responseDest); + _destinationProducer = _producerSession.createProducer(responseDest); _destinationProducer.setDisableMessageTimestamp(true); - _destinationProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + _destinationProducer.setDeliveryMode(deliveryMode); _logger.info("After create a producer"); } } @@ -127,7 +139,7 @@ public class ServiceProvidingClient try { String payload = "This is a response: sing together: 'Mahnah mahnah...'" + tm.getText(); - TextMessage msg = session.createTextMessage(payload); + TextMessage msg = _producerSession.createTextMessage(payload); if (tm.propertyExists("timeSent")) { _logger.info("timeSent property set on message"); @@ -135,6 +147,15 @@ public class ServiceProvidingClient msg.setStringProperty("timeSent", tm.getStringProperty("timeSent")); } _destinationProducer.send(msg); + + if(_isTransactional) + { + _producerSession.commit(); + } + if(_isTransactional) + { + _session.commit(); + } if (_messageCount % 1000 == 0) { _logger.info("Sent response to '" + _responseDest + "'"); @@ -158,9 +179,9 @@ public class ServiceProvidingClient { _logger.info("Starting..."); - if (args.length < 5) + if (args.length < 7) { - System.out.println("Usage: brokerDetails username password virtual-path serviceQueue [selector]"); + System.out.println("Usage: brokerDetails username password virtual-path serviceQueue [selector]"); System.exit(1); } String clientId = null; @@ -177,7 +198,7 @@ public class ServiceProvidingClient try { ServiceProvidingClient client = new ServiceProvidingClient(args[0], args[1], args[2], - clientId, args[3], args[4]); + clientId, args[3], args[4], args[5], args[6]); client.run(); } catch (JMSException e) diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java index 93e2d4685b..b58b8eb0ef 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java @@ -53,10 +53,12 @@ public class ServiceRequestingClient implements ExceptionListener private AMQConnection _connection; private Session _session; + private Session _producerSession; private long _averageLatency; private int _messageCount; + private boolean _isTransactional; private volatile boolean _completed; @@ -106,7 +108,7 @@ public class ServiceRequestingClient implements ExceptionListener } try { - m.getPropertyNames(); + m.getPropertyNames(); if (m.propertyExists("timeSent")) { long timeSent = Long.parseLong(m.getStringProperty("timeSent")); @@ -122,6 +124,10 @@ public class ServiceRequestingClient implements ExceptionListener _averageLatency = (_averageLatency + (now - timeSent)) / 2; _log.info("Average latency now: " + _averageLatency); } + } + if(_isTransactional) + { + _session.commit(); } } catch (JMSException e) @@ -168,24 +174,33 @@ public class ServiceRequestingClient implements ExceptionListener } public ServiceRequestingClient(String brokerHosts, String clientID, String username, String password, - String vpath, String commandQueueName, + String vpath, String commandQueueName, + String deliveryModeString, String transactedMode, final int messageCount, final int messageDataLength) throws AMQException, URLSyntaxException { + final int deliveryMode = deliveryModeString.toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT + : DeliveryMode.NON_PERSISTENT; + + _isTransactional = transactedMode.toUpperCase().charAt(0) == 'T' ? true : false; + + _log.info("Delivery Mode: " + deliveryMode + "\t isTransactional: " + _isTransactional); + _messageCount = messageCount; MESSAGE_DATA = createMessagePayload(messageDataLength); try { createConnection(brokerHosts, clientID, username, password, vpath); - _session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _session = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE); + _producerSession = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE); _connection.setExceptionListener(this); AMQQueue destination = new AMQQueue(commandQueueName); - _producer = (MessageProducer) _session.createProducer(destination); + _producer = (MessageProducer) _producerSession.createProducer(destination); _producer.setDisableMessageTimestamp(true); - _producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + _producer.setDeliveryMode(deliveryMode); _tempDestination = new AMQQueue("TempResponse" + Long.toString(System.currentTimeMillis()), true); @@ -196,6 +211,10 @@ public class ServiceRequestingClient implements ExceptionListener TextMessage first = _session.createTextMessage(MESSAGE_DATA); first.setJMSReplyTo(_tempDestination); _producer.send(first); + if(_isTransactional) + { + _producerSession.commit(); + } try { Thread.sleep(1000); @@ -227,7 +246,7 @@ public class ServiceRequestingClient implements ExceptionListener _connection.start(); for (int i = 1; i < _messageCount; i++) { - TextMessage msg = _session.createTextMessage(MESSAGE_DATA + i); + TextMessage msg = _producerSession.createTextMessage(MESSAGE_DATA + i); msg.setJMSReplyTo(_tempDestination); if (i % 1000 == 0) { @@ -235,6 +254,11 @@ public class ServiceRequestingClient implements ExceptionListener msg.setStringProperty("timeSent", String.valueOf(timeNow)); } _producer.send(msg); + if(_isTransactional) + { + _producerSession.commit(); + } + } _log.info("Finished sending " + _messageCount + " messages"); } @@ -260,17 +284,17 @@ public class ServiceRequestingClient implements ExceptionListener if (args.length < 6) { System.err.println( - "Usage: ServiceRequestingClient "); + "Usage: ServiceRequestingClient "); System.exit(1); } try { - int messageDataLength = args.length > 6 ? Integer.parseInt(args[6]) : 4096; + int messageDataLength = args.length > 8 ? Integer.parseInt(args[8]) : 4096; InetAddress address = InetAddress.getLocalHost(); String clientID = address.getHostName() + System.currentTimeMillis(); ServiceRequestingClient client = new ServiceRequestingClient(args[0], clientID, args[1], args[2], args[3], - args[4], Integer.parseInt(args[5]), + args[4], args[5], args[6], Integer.parseInt(args[7]), messageDataLength); Object waiter = new Object(); client.run(waiter); -- cgit v1.2.1 From b9793145de06dcf466cf9794250372d2100c2efe Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 11 Jan 2007 19:12:15 +0000 Subject: QPID-32: fixed test not to use string properties on the messages with timestamps git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495337 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/ServiceProvidingClient.java | 15 ++++++++------- .../apache/qpid/requestreply/ServiceRequestingClient.java | 14 +++++++------- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java index a261d8e5da..84cfc8934f 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java @@ -7,9 +7,9 @@ * 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 @@ -48,7 +48,7 @@ public class ServiceProvidingClient private boolean _isTransactional; public ServiceProvidingClient(String brokerDetails, String username, String password, - String clientName, String virtualPath, String serviceName, + String clientName, String virtualPath, String serviceName, String deliveryModeString, String transactedMode) throws AMQException, JMSException, URLSyntaxException { @@ -56,7 +56,7 @@ public class ServiceProvidingClient _isTransactional = transactedMode.toUpperCase().charAt(0) == 'T' ? true : false; _logger.info("Delivery Mode: " + deliveryMode + "\t isTransactional: " + _isTransactional); - + _connection = new AMQConnection(brokerDetails, username, password, clientName, virtualPath); _connection.setConnectionListener(new ConnectionListener() @@ -143,11 +143,12 @@ public class ServiceProvidingClient if (tm.propertyExists("timeSent")) { _logger.info("timeSent property set on message"); - _logger.info("timeSent value is: " + tm.getLongProperty("timeSent")); - msg.setStringProperty("timeSent", tm.getStringProperty("timeSent")); + long timesent = tm.getLongProperty("timeSent"); + _logger.info("timeSent value is: " + timesent); + msg.setLongProperty("timeSent", timesent); } _destinationProducer.send(msg); - + if(_isTransactional) { _producerSession.commit(); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java index b58b8eb0ef..1da81f9fc2 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java @@ -7,9 +7,9 @@ * 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 @@ -174,13 +174,13 @@ public class ServiceRequestingClient implements ExceptionListener } public ServiceRequestingClient(String brokerHosts, String clientID, String username, String password, - String vpath, String commandQueueName, + String vpath, String commandQueueName, String deliveryModeString, String transactedMode, final int messageCount, final int messageDataLength) throws AMQException, URLSyntaxException { - final int deliveryMode = deliveryModeString.toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT + final int deliveryMode = deliveryModeString.toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT; - + _isTransactional = transactedMode.toUpperCase().charAt(0) == 'T' ? true : false; _log.info("Delivery Mode: " + deliveryMode + "\t isTransactional: " + _isTransactional); @@ -251,12 +251,12 @@ public class ServiceRequestingClient implements ExceptionListener if (i % 1000 == 0) { long timeNow = System.currentTimeMillis(); - msg.setStringProperty("timeSent", String.valueOf(timeNow)); + msg.setLongProperty("timeSent", timeNow); } _producer.send(msg); if(_isTransactional) { - _producerSession.commit(); + _producerSession.commit(); } } -- cgit v1.2.1 From 3b44f4817b0c26bb798a1ad450b1fb6017d9beb7 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 12 Jan 2007 08:52:31 +0000 Subject: QPID-282 Updated AMQConnection and AMQBrokerDetails to check the host:port and add tcp:// if there is no protocol specified. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495517 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java index 1da81f9fc2..7cbbbfe9b0 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java @@ -281,7 +281,7 @@ public class ServiceRequestingClient implements ExceptionListener */ public static void main(String[] args) { - if (args.length < 6) + if (args.length < 9) { System.err.println( "Usage: ServiceRequestingClient "); -- cgit v1.2.1 From 65bd33de73b748da028be20507798573fbdbfa5a Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Fri, 12 Jan 2007 09:43:09 +0000 Subject: Adding a volume test script(volumetestServiceRequestingClient.sh) This script checks if all the messages were sent received back successfully. ServiceRequestingClient.java and ServiceProvidingClient.java modified to add a message identifier to match the request and response message. log4j file modified to create a log file git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495532 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/requestreply/ServiceProvidingClient.java | 20 +++++---- .../qpid/requestreply/ServiceRequestingClient.java | 52 ++++++++++------------ 2 files changed, 34 insertions(+), 38 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java index 84cfc8934f..66950ddf3e 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java @@ -21,11 +21,11 @@ package org.apache.qpid.requestreply; import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.jms.Session; import org.apache.qpid.jms.ConnectionListener; -import org.apache.qpid.AMQException; +import org.apache.qpid.jms.Session; import org.apache.qpid.url.URLSyntaxException; import javax.jms.*; @@ -35,7 +35,7 @@ import java.net.UnknownHostException; public class ServiceProvidingClient { private static final Logger _logger = Logger.getLogger(ServiceProvidingClient.class); - + private static final String MESSAGE_IDENTIFIER = "MessageIdentifier"; private MessageProducer _destinationProducer; private Destination _responseDest; @@ -102,9 +102,7 @@ public class ServiceProvidingClient public void onMessage(Message message) { //_logger.info("Got message '" + message + "'"); - TextMessage tm = (TextMessage) message; - try { Destination responseDest = tm.getJMSReplyTo(); @@ -147,6 +145,12 @@ public class ServiceProvidingClient _logger.info("timeSent value is: " + timesent); msg.setLongProperty("timeSent", timesent); } + // this identifier set in the serviceRequestingClient is used to match the response with the request + if (tm.propertyExists(MESSAGE_IDENTIFIER)) + { + msg.setIntProperty(MESSAGE_IDENTIFIER, tm.getIntProperty(MESSAGE_IDENTIFIER)); + } + _destinationProducer.send(msg); if(_isTransactional) @@ -182,7 +186,8 @@ public class ServiceProvidingClient if (args.length < 7) { - System.out.println("Usage: brokerDetails username password virtual-path serviceQueue [selector]"); + System.out.println("Usage: " + + " [selector]"); System.exit(1); } String clientId = null; @@ -214,9 +219,6 @@ public class ServiceProvidingClient { _logger.error("Error: " + e, e); } - - - } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java index 7cbbbfe9b0..de49124035 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java @@ -22,13 +22,14 @@ package org.apache.qpid.requestreply; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.url.URLSyntaxException; import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.jms.MessageConsumer; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; +import org.apache.qpid.url.URLSyntaxException; import javax.jms.*; import java.net.InetAddress; @@ -46,8 +47,8 @@ public class ServiceRequestingClient implements ExceptionListener { private static final Logger _log = Logger.getLogger(ServiceRequestingClient.class); - private static final String MESSAGE_DATA_BYTES = "jfd ghljgl hjvhlj cvhvjf ldhfsj lhfdsjf hldsjfk hdslkfj hsdflk "; - + private static final String MESSAGE_IDENTIFIER = "MessageIdentifier"; + private static int _messageIdentifier = 0; private String MESSAGE_DATA; private AMQConnection _connection; @@ -68,24 +69,6 @@ public class ServiceRequestingClient implements ExceptionListener private Object _waiter; - private static String createMessagePayload(int size) - { - _log.info("Message size set to " + size + " bytes"); - StringBuffer buf = new StringBuffer(size); - int count = 0; - while (count < size + MESSAGE_DATA_BYTES.length()) - { - buf.append(MESSAGE_DATA_BYTES); - count += MESSAGE_DATA_BYTES.length(); - } - if (count < size) - { - buf.append(MESSAGE_DATA_BYTES, 0, size - count); - } - - return buf.toString(); - } - private class CallbackHandler implements MessageListener { private int _expectedMessageCount; @@ -125,7 +108,11 @@ public class ServiceRequestingClient implements ExceptionListener _log.info("Average latency now: " + _averageLatency); } } - if(_isTransactional) + if (m.propertyExists(MESSAGE_IDENTIFIER)) + { + _log.info("Received Message Identifier: " + m.getIntProperty(MESSAGE_IDENTIFIER)); + } + if(_isTransactional) { _session.commit(); } @@ -186,7 +173,7 @@ public class ServiceRequestingClient implements ExceptionListener _log.info("Delivery Mode: " + deliveryMode + "\t isTransactional: " + _isTransactional); _messageCount = messageCount; - MESSAGE_DATA = createMessagePayload(messageDataLength); + MESSAGE_DATA = TestMessageFactory.createMessagePayload(messageDataLength); try { createConnection(brokerHosts, clientID, username, password, vpath); @@ -210,7 +197,7 @@ public class ServiceRequestingClient implements ExceptionListener //Send first message, then wait a bit to allow the provider to get initialised TextMessage first = _session.createTextMessage(MESSAGE_DATA); first.setJMSReplyTo(_tempDestination); - _producer.send(first); + send(first); if(_isTransactional) { _producerSession.commit(); @@ -234,6 +221,13 @@ public class ServiceRequestingClient implements ExceptionListener } } + private void send(TextMessage msg) throws JMSException + { + msg.setIntProperty(MESSAGE_IDENTIFIER, ++_messageIdentifier); + _producer.send(msg); + _log.info("Sent Message Identifier: " + _messageIdentifier); + } + /** * Run the test and notify an object upon receipt of all responses. * @@ -253,7 +247,7 @@ public class ServiceRequestingClient implements ExceptionListener long timeNow = System.currentTimeMillis(); msg.setLongProperty("timeSent", timeNow); } - _producer.send(msg); + send(msg); if(_isTransactional) { _producerSession.commit(); @@ -283,8 +277,9 @@ public class ServiceRequestingClient implements ExceptionListener { if (args.length < 9) { - System.err.println( - "Usage: ServiceRequestingClient "); + System.err.println("Usage: ServiceRequestingClient " + + " " + + " "); System.exit(1); } try @@ -305,7 +300,6 @@ public class ServiceRequestingClient implements ExceptionListener waiter.wait(); } } - } catch (UnknownHostException e) { -- cgit v1.2.1 From ad2ef7dd355d3cefb2af8e822c0f927e9a4afc74 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 12 Jan 2007 11:10:48 +0000 Subject: QPID-278 broker distribution - modified to allow assembly:directory builds broker/pom.xml - moved slf4j to common/pom.xml QPID-283 Provided better feedback from shell scripts. Provided QuickTest shell script that runs the RequestReply tests. perftests distribution - modified to allow assembly:directory builds Moved Resource Readme content relating to Tests to RunningPerformanceTests.txt git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495554 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/requestreply/ServiceProvidingClient.java | 42 +++++++++++++++------ .../qpid/requestreply/ServiceRequestingClient.java | 44 ++++++++++++++-------- 2 files changed, 59 insertions(+), 27 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java index 66950ddf3e..00528c3a5d 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java @@ -49,13 +49,13 @@ public class ServiceProvidingClient public ServiceProvidingClient(String brokerDetails, String username, String password, String clientName, String virtualPath, String serviceName, - String deliveryModeString, String transactedMode) + final int deliveryMode, boolean transactedMode, String selector) throws AMQException, JMSException, URLSyntaxException { - final int deliveryMode = deliveryModeString.toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT; - _isTransactional = transactedMode.toUpperCase().charAt(0) == 'T' ? true : false; + _isTransactional = transactedMode; - _logger.info("Delivery Mode: " + deliveryMode + "\t isTransactional: " + _isTransactional); + _logger.info("Delivery Mode: " + (deliveryMode == DeliveryMode.NON_PERSISTENT ? "Non Persistent" : "Persistent") + + "\t isTransactional: " + _isTransactional); _connection = new AMQConnection(brokerDetails, username, password, clientName, virtualPath); @@ -93,7 +93,7 @@ public class ServiceProvidingClient AMQQueue destination = new AMQQueue(serviceName); MessageConsumer consumer = _session.createConsumer(destination, - 100, true, false, null); + 100, true, false, selector); consumer.setMessageListener(new MessageListener() { @@ -153,11 +153,11 @@ public class ServiceProvidingClient _destinationProducer.send(msg); - if(_isTransactional) + if (_isTransactional) { _producerSession.commit(); } - if(_isTransactional) + if (_isTransactional) { _session.commit(); } @@ -184,10 +184,9 @@ public class ServiceProvidingClient { _logger.info("Starting..."); - if (args.length < 7) + if (args.length < 5) { - System.out.println("Usage: " + - " [selector]"); + System.out.println("Usage: serviceProvidingClient [ ] [selector]"); System.exit(1); } String clientId = null; @@ -201,10 +200,29 @@ public class ServiceProvidingClient _logger.error("Error: " + e, e); } + + int deliveryMode = DeliveryMode.NON_PERSISTENT; + boolean transactedMode = false; + + if (args.length > 7) + { + deliveryMode = args[args.length - 2].toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT + : DeliveryMode.NON_PERSISTENT; + + transactedMode = args[args.length - 1].toUpperCase().charAt(0) == 'T' ? true : false; + } + + String selector = null; + if ((args.length == 8) || (args.length == 7)) + { + selector = args[args.length - 1]; + } + try { ServiceProvidingClient client = new ServiceProvidingClient(args[0], args[1], args[2], - clientId, args[3], args[4], args[5], args[6]); + clientId, args[3], args[4], + deliveryMode, transactedMode, selector); client.run(); } catch (JMSException e) @@ -219,6 +237,8 @@ public class ServiceProvidingClient { _logger.error("Error: " + e, e); } + + } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java index de49124035..2c1c0ecff6 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java @@ -91,7 +91,7 @@ public class ServiceRequestingClient implements ExceptionListener } try { - m.getPropertyNames(); + m.getPropertyNames(); if (m.propertyExists("timeSent")) { long timeSent = Long.parseLong(m.getStringProperty("timeSent")); @@ -162,15 +162,13 @@ public class ServiceRequestingClient implements ExceptionListener public ServiceRequestingClient(String brokerHosts, String clientID, String username, String password, String vpath, String commandQueueName, - String deliveryModeString, String transactedMode, + int deliveryMode, boolean transactedMode, final int messageCount, final int messageDataLength) throws AMQException, URLSyntaxException { - final int deliveryMode = deliveryModeString.toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT - : DeliveryMode.NON_PERSISTENT; + _isTransactional = transactedMode; - _isTransactional = transactedMode.toUpperCase().charAt(0) == 'T' ? true : false; - - _log.info("Delivery Mode: " + deliveryMode + "\t isTransactional: " + _isTransactional); + _log.info("Delivery Mode: " + (deliveryMode == DeliveryMode.NON_PERSISTENT ? "Non Persistent" : "Persistent") + + "\t isTransactional: " + _isTransactional); _messageCount = messageCount; MESSAGE_DATA = TestMessageFactory.createMessagePayload(messageDataLength); @@ -198,7 +196,7 @@ public class ServiceRequestingClient implements ExceptionListener TextMessage first = _session.createTextMessage(MESSAGE_DATA); first.setJMSReplyTo(_tempDestination); send(first); - if(_isTransactional) + if (_isTransactional) { _producerSession.commit(); } @@ -248,7 +246,7 @@ public class ServiceRequestingClient implements ExceptionListener msg.setLongProperty("timeSent", timeNow); } send(msg); - if(_isTransactional) + if (_isTransactional) { _producerSession.commit(); } @@ -275,22 +273,36 @@ public class ServiceRequestingClient implements ExceptionListener */ public static void main(String[] args) { - if (args.length < 9) + if (args.length < 6) { - System.err.println("Usage: ServiceRequestingClient " + - " " + - " "); + System.err.println( + "Usage: ServiceRequestingClient [] [ ]"); System.exit(1); } try { - int messageDataLength = args.length > 8 ? Integer.parseInt(args[8]) : 4096; + int messageSize = 4096; + boolean transactedMode = false; + int deliveryMode = DeliveryMode.NON_PERSISTENT; + + if (args.length > 7) + { + deliveryMode = args[args.length - 2].toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT + : DeliveryMode.NON_PERSISTENT; + + transactedMode = args[args.length - 1].toUpperCase().charAt(0) == 'T' ? true : false; + } + + if ((args.length == 9) ||(args.length == 7)) + { + messageSize = Integer.parseInt(args[6]); + } InetAddress address = InetAddress.getLocalHost(); String clientID = address.getHostName() + System.currentTimeMillis(); ServiceRequestingClient client = new ServiceRequestingClient(args[0], clientID, args[1], args[2], args[3], - args[4], args[5], args[6], Integer.parseInt(args[7]), - messageDataLength); + args[4], deliveryMode, transactedMode, Integer.parseInt(args[5]), + messageSize); Object waiter = new Object(); client.run(waiter); synchronized (waiter) -- cgit v1.2.1 From fc24610c89ee8e4a983a59f6dc1d9e7a47217c0c Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 12 Jan 2007 14:44:20 +0000 Subject: QPID-283 Documented topic test Updated perftests.log4j to include log level in output to make it clear when there is a non test output Fixed bug in Publisher where batches of 2 would result in a div by zero error. scripts created and edited to use the amqj.test.logging.level. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@495584 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/topic/Publisher.java | 31 +++++++++++++++------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java index d788029ee9..c3b19b558a 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java @@ -51,7 +51,7 @@ public class Publisher implements MessageListener _factory.createControlConsumer().setMessageListener(this); _connection.start(); - if(warmup > 0) + if (warmup > 0) { System.out.println("Runing warmup (" + warmup + " msgs)"); long time = batch(warmup, consumerCount); @@ -59,11 +59,14 @@ public class Publisher implements MessageListener } long[] times = new long[batches]; - for(int i = 0; i < batches; i++) + for (int i = 0; i < batches; i++) { - if(i > 0) Thread.sleep(delay*1000); + if (i > 0) + { + Thread.sleep(delay * 1000); + } times[i] = batch(msgCount, consumerCount); - System.out.println("Batch " + (i+1) + " of " + batches + " completed in " + times[i] + " ms."); + System.out.println("Batch " + (i + 1) + " of " + batches + " completed in " + times[i] + " ms."); } long min = min(times); @@ -131,7 +134,7 @@ public class Publisher implements MessageListener static long min(long[] times) { long min = times.length > 0 ? times[0] : 0; - for(int i = 0; i < times.length; i++) + for (int i = 0; i < times.length; i++) { min = Math.min(min, times[i]); } @@ -141,7 +144,7 @@ public class Publisher implements MessageListener static long max(long[] times) { long max = times.length > 0 ? times[0] : 0; - for(int i = 0; i < times.length; i++) + for (int i = 0; i < times.length; i++) { max = Math.max(max, times[i]); } @@ -151,14 +154,22 @@ public class Publisher implements MessageListener static long avg(long[] times, long min, long max) { long sum = 0; - for(int i = 0; i < times.length; i++) + for (int i = 0; i < times.length; i++) { sum += times[i]; } - sum -= min; - sum -= max; - return (sum / (times.length - 2)); + int adjustment = 0; + + // Remove min and max if we have run enough batches. + if (times.length > 2) + { + sum -= min; + sum -= max; + adjustment = 2; + } + + return (sum / (times.length - adjustment)); } public static void main(String[] argv) throws Exception -- cgit v1.2.1 From 477f2b553060d8840583bfadd9a5bc53610cef81 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Mon, 15 Jan 2007 09:39:38 +0000 Subject: checking for the AMQ MessageID of received message in ServiceRequestingClient.java git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@496260 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/requestreply/ServiceProvidingClient.java | 14 +------ .../qpid/requestreply/ServiceRequestingClient.java | 49 +++++++++++++--------- 2 files changed, 32 insertions(+), 31 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java index 00528c3a5d..bab732e2a6 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java @@ -35,7 +35,7 @@ import java.net.UnknownHostException; public class ServiceProvidingClient { private static final Logger _logger = Logger.getLogger(ServiceProvidingClient.class); - private static final String MESSAGE_IDENTIFIER = "MessageIdentifier"; + private MessageProducer _destinationProducer; private Destination _responseDest; @@ -57,8 +57,7 @@ public class ServiceProvidingClient _logger.info("Delivery Mode: " + (deliveryMode == DeliveryMode.NON_PERSISTENT ? "Non Persistent" : "Persistent") + "\t isTransactional: " + _isTransactional); - _connection = new AMQConnection(brokerDetails, username, password, - clientName, virtualPath); + _connection = new AMQConnection(brokerDetails, username, password, clientName, virtualPath); _connection.setConnectionListener(new ConnectionListener() { @@ -145,11 +144,6 @@ public class ServiceProvidingClient _logger.info("timeSent value is: " + timesent); msg.setLongProperty("timeSent", timesent); } - // this identifier set in the serviceRequestingClient is used to match the response with the request - if (tm.propertyExists(MESSAGE_IDENTIFIER)) - { - msg.setIntProperty(MESSAGE_IDENTIFIER, tm.getIntProperty(MESSAGE_IDENTIFIER)); - } _destinationProducer.send(msg); @@ -200,7 +194,6 @@ public class ServiceProvidingClient _logger.error("Error: " + e, e); } - int deliveryMode = DeliveryMode.NON_PERSISTENT; boolean transactedMode = false; @@ -237,9 +230,6 @@ public class ServiceProvidingClient { _logger.error("Error: " + e, e); } - - } - } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java index 2c1c0ecff6..7d4b5eb24f 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java @@ -26,6 +26,7 @@ import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.client.message.JMSTextMessage; import org.apache.qpid.jms.MessageConsumer; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; @@ -47,8 +48,7 @@ public class ServiceRequestingClient implements ExceptionListener { private static final Logger _log = Logger.getLogger(ServiceRequestingClient.class); - private static final String MESSAGE_IDENTIFIER = "MessageIdentifier"; - private static int _messageIdentifier = 0; + private long _messageIdentifier = 0; private String MESSAGE_DATA; private AMQConnection _connection; @@ -108,10 +108,6 @@ public class ServiceRequestingClient implements ExceptionListener _log.info("Average latency now: " + _averageLatency); } } - if (m.propertyExists(MESSAGE_IDENTIFIER)) - { - _log.info("Received Message Identifier: " + m.getIntProperty(MESSAGE_IDENTIFIER)); - } if(_isTransactional) { _session.commit(); @@ -127,6 +123,7 @@ public class ServiceRequestingClient implements ExceptionListener _log.info("Received message count: " + _actualMessageCount); } + checkForMessageID(m); if (_actualMessageCount == _expectedMessageCount) { _completed = true; @@ -149,6 +146,30 @@ public class ServiceRequestingClient implements ExceptionListener } } + /** + * Checks if the received AMQ Message ID(delivery tag) is in sequence, by comparing it with the AMQ MessageID + * of previous message. + * @param receivedMsg + */ + private void checkForMessageID(Message receivedMsg) + { + try + { + JMSTextMessage msg = (JMSTextMessage)receivedMsg; + if (! (msg.getDeliveryTag() == _messageIdentifier + 1)) + { + _log.info("Out of sequence message received. Previous AMQ MessageID= " + _messageIdentifier + + ", Received AMQ messageID= " + receivedMsg.getJMSMessageID()); + } + _messageIdentifier = msg.getDeliveryTag(); + } + catch (Exception ex) + { + _log.error("Error in checking messageID ", ex); + } + + } + private void notifyWaiter() { if (_waiter != null) @@ -178,10 +199,8 @@ public class ServiceRequestingClient implements ExceptionListener _session = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE); _producerSession = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE); - _connection.setExceptionListener(this); - AMQQueue destination = new AMQQueue(commandQueueName); _producer = (MessageProducer) _producerSession.createProducer(destination); _producer.setDisableMessageTimestamp(true); @@ -195,7 +214,7 @@ public class ServiceRequestingClient implements ExceptionListener //Send first message, then wait a bit to allow the provider to get initialised TextMessage first = _session.createTextMessage(MESSAGE_DATA); first.setJMSReplyTo(_tempDestination); - send(first); + _producer.send(first); if (_isTransactional) { _producerSession.commit(); @@ -219,13 +238,6 @@ public class ServiceRequestingClient implements ExceptionListener } } - private void send(TextMessage msg) throws JMSException - { - msg.setIntProperty(MESSAGE_IDENTIFIER, ++_messageIdentifier); - _producer.send(msg); - _log.info("Sent Message Identifier: " + _messageIdentifier); - } - /** * Run the test and notify an object upon receipt of all responses. * @@ -245,7 +257,7 @@ public class ServiceRequestingClient implements ExceptionListener long timeNow = System.currentTimeMillis(); msg.setLongProperty("timeSent", timeNow); } - send(msg); + _producer.send(msg); if (_isTransactional) { _producerSession.commit(); @@ -263,8 +275,7 @@ public class ServiceRequestingClient implements ExceptionListener private void createConnection(String brokerHosts, String clientID, String username, String password, String vpath) throws AMQException, URLSyntaxException { - _connection = new AMQConnection(brokerHosts, username, password, - clientID, vpath); + _connection = new AMQConnection(brokerHosts, username, password, clientID, vpath); } /** -- cgit v1.2.1 From 45021e2261240385a99889c48294debc639746de Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Tue, 16 Jan 2007 15:34:03 +0000 Subject: Tests under this directory are actually ping tests -Comment from Rupert git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@496731 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/ping/TestPingClient.java | 138 ++++++++++++ .../org/apache/qpid/ping/TestPingProducer.java | 243 +++++++++++++++++++++ .../org/apache/qpid/ping/TestPingPublisher.java | 197 +++++++++++++++++ .../org/apache/qpid/ping/TestPingSubscriber.java | 134 ++++++++++++ .../org/apache/qpid/pingpong/TestPingClient.java | 138 ------------ .../org/apache/qpid/pingpong/TestPingProducer.java | 243 --------------------- .../apache/qpid/pingpong/TestPingPublisher.java | 197 ----------------- .../apache/qpid/pingpong/TestPingSubscriber.java | 134 ------------ 8 files changed, 712 insertions(+), 712 deletions(-) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingPublisher.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingClient.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingProducer.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingPublisher.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingSubscriber.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java new file mode 100644 index 0000000000..c96f6bd61d --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java @@ -0,0 +1,138 @@ +/* + * + * 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.qpid.pingpong; + +import org.apache.log4j.Logger; +import org.apache.log4j.Level; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.jms.Session; + +import javax.jms.*; +import java.net.InetAddress; + +public class TestPingClient +{ + private static final Logger _logger = Logger.getLogger(TestPingClient.class); + + private static class TestPingMessageListener implements MessageListener + { + public TestPingMessageListener() + { + } + + long _lastTimestamp = 0L; + long _lastTimestampString = 0L; + + public void onMessage(javax.jms.Message message) + { + if (_logger.isInfoEnabled()) + { + long timestamp = 0L; + long timestampString = 0L; + + try + { + timestamp = message.getLongProperty("timestamp"); + timestampString = Long.parseLong(message.getStringProperty("timestampString")); + + if (timestampString != timestamp) + { + _logger.info("Timetamps differ!:\n" + + "timestamp:" + timestamp + "\n" + + "timestampString:" + timestampString); + } + + } + catch (JMSException jmse) + { + //ignore + } + + long diff = timestamp - _lastTimestamp; + _lastTimestamp = timestamp; + + long stringDiff = timestampString - _lastTimestampString; + + _lastTimestampString = timestampString; + + _logger.info("Ping: T:" + diff + "ms, TS:" + stringDiff); + + // _logger.info(_name + " got message '" + message + "\n"); + } + } + } + + public static void main(String[] args) + { + _logger.setLevel(Level.INFO); + + _logger.info("Starting..."); + + if (args.length < 4) + { + System.out.println("Usage: brokerdetails username password virtual-path [selector] "); + System.exit(1); + } + try + { + InetAddress address = InetAddress.getLocalHost(); + AMQConnection con1 = new AMQConnection(args[0], args[1], args[2], + address.getHostName(), args[3]); + + + _logger.info("Connected with URL:" + con1.toURL()); + + final org.apache.qpid.jms.Session session1 = (org.apache.qpid.jms.Session) + con1.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + String selector = null; + + if (args.length == 5) + { + selector = args[4]; + _logger.info("Message selector is <" + selector + ">..."); + } + else + { + _logger.info("Not using message selector"); + } + + + Queue q = new AMQQueue("ping"); + + MessageConsumer consumer1 = session1.createConsumer(q, + 1, false, false, selector); + + consumer1.setMessageListener(new TestPingMessageListener()); + con1.start(); + } + catch (Throwable t) + { + System.err.println("Fatal error: " + t); + t.printStackTrace(); + } + + System.out.println("Waiting..."); + } +} + diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java new file mode 100644 index 0000000000..bb9e17615e --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java @@ -0,0 +1,243 @@ +/* + * + * 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.qpid.pingpong; + +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.AMQException; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.qpid.client.AMQNoConsumersException; +import org.apache.qpid.client.BasicMessageProducer; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.jms.MessageProducer; +import org.apache.qpid.jms.Session; + +import javax.jms.*; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * A client that behaves as follows: + *
    • Connects to a queue, whose name is specified as a cmd-line argument
    • + *
    • Creates a temporary queue
    • + *
    • Creates messages containing a property that is the name of the temporary queue
    • + *
    • Fires off a message on the original queue and waits for a response on the temporary queue
    • + *
    + */ +public class TestPingProducer implements ExceptionListener +{ + private static final Logger _log = Logger.getLogger(TestPingProducer.class); + + private AMQConnection _connection; + + private static int _messageSize = 0; + private boolean _publish; + + private long SLEEP_TIME = 250L; + +// private class CallbackHandler implements MessageListener +// { +// +// private int _actualMessageCount; +// +// +// public void onMessage(Message m) +// { +// if (_log.isDebugEnabled()) +// { +// _log.debug("Message received: " + m); +// } +// _actualMessageCount++; +// if (_actualMessageCount % 1000 == 0) +// { +// _log.info("Received message count: " + _actualMessageCount); +// } +// } +// } + + public TestPingProducer(boolean TRANSACTED, String brokerDetails, String clientID, + String virtualpath) throws AMQException, URLSyntaxException + { + try + { + createConnection(brokerDetails, clientID, virtualpath); + + Session session; + + if (TRANSACTED) + { + session = (Session) _connection.createSession(true, Session.SESSION_TRANSACTED); + } + else + { + session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + String queue = "ping"; + AMQQueue destination = new AMQQueue(queue); + MessageProducer producer = (MessageProducer) session.createProducer(destination); + + _connection.setExceptionListener(this); + + _connection.start(); + + while (_publish) + { +/* + TextMessage msg = session.createTextMessage( + "Presented to in conjunction with Mahnah Mahnah and the Snowths: " + ++messageNumber); +*/ + ObjectMessage msg = null; + if (_messageSize != 0) + { + msg = TestMessageFactory.newObjectMessage(session, _messageSize); + } + else + { + msg = session.createObjectMessage(); + } + + msg.setStringProperty("timestampString", Long.toString(System.currentTimeMillis())); + msg.setLongProperty("timestamp", System.currentTimeMillis()); + + ((BasicMessageProducer) producer).send(msg, DeliveryMode.NON_PERSISTENT, true); + _log.info("Message Sent."); + _log.debug(msg); + + + if (TRANSACTED) + { + try + { + session.commit(); + _log.debug("Session Commited."); + } + catch (JMSException e) + { + _log.trace("JMSException on commit:" + e); + try + { + session.rollback(); + _log.debug("Message rolled back."); + } + catch (JMSException jsme) + { + _log.trace("JMSE on rollback:" + jsme); + } + + + if (e.getLinkedException() instanceof AMQNoConsumersException) + { + _log.info("No Consumers on queue:'" + queue + "'"); + continue; + } + } + } + + + if (SLEEP_TIME > 0) + { + try + { + Thread.sleep(SLEEP_TIME); + } + catch (InterruptedException ie) + { + //do nothing + } + } + + + } + + } + catch (JMSException e) + { + _publish = false; + e.printStackTrace(); + } + } + + private void createConnection(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException + { + _publish = true; + _connection = new AMQConnection(brokerDetails, "guest", "guest", + clientID, virtualpath); + _log.info("Connected with URL:" + _connection.toURL()); + } + + /** + * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank + * means the server will allocate a name. + */ + public static void main(String[] args) + { + if (args.length < 2) + { + System.err.println("Usage: TestPingPublisher [transacted] [message size in bytes]"); + System.exit(0); + } + try + { + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); + boolean transacted = false; + if (args.length == 3 ) + { + transacted = Boolean.parseBoolean(args[2]); + } + else if (args.length > 3 ) + { + transacted = Boolean.parseBoolean(args[2]); + _messageSize = Integer.parseInt(args[3]); + } + + new TestPingProducer(transacted, args[0], clientID, args[1]); + } + catch (UnknownHostException e) + { + e.printStackTrace(); + } + catch (AMQException e) + { + System.err.println("Error in client: " + e); + e.printStackTrace(); + } + catch (URLSyntaxException e) + { + System.err.println("Error in connection arguments : " + e); + } + + //System.exit(0); + } + + /** + * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) + */ + public void onException(JMSException e) + { + System.err.println(e.getMessage()); + + _publish = false; + e.printStackTrace(System.err); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingPublisher.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingPublisher.java new file mode 100644 index 0000000000..3b2dcc4d36 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingPublisher.java @@ -0,0 +1,197 @@ +/* + * + * 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.qpid.pingpong; + +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.AMQException; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.BasicMessageProducer; +import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.jms.MessageProducer; +import org.apache.qpid.jms.Session; + +import javax.jms.*; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * A client that behaves as follows: + *
    • Connects to a queue, whose name is specified as a cmd-line argument
    • + *
    • Creates a temporary queue
    • + *
    • Creates messages containing a property that is the name of the temporary queue
    • + *
    • Fires off a message on the original queue and waits for a response on the temporary queue
    • + *
    + */ +public class TestPingPublisher implements ExceptionListener +{ + private static final Logger _log = Logger.getLogger(TestPingPublisher.class); + + private AMQConnection _connection; + + private boolean _publish; + private static int _messageSize = 0; + private long SLEEP_TIME = 0L; + +// private class CallbackHandler implements MessageListener +// { +// +// private int _actualMessageCount; +// +// +// public void onMessage(Message m) +// { +// if (_log.isDebugEnabled()) +// { +// _log.debug("Message received: " + m); +// } +// _actualMessageCount++; +// if (_actualMessageCount % 1000 == 0) +// { +// _log.info("Received message count: " + _actualMessageCount); +// } +// } +// } + + public TestPingPublisher(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException + { + try + { + createConnection(brokerDetails, clientID, virtualpath); + + Session session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + //AMQQueue destination = new AMQQueue("ping"); + AMQTopic destination = new AMQTopic("ping"); + MessageProducer producer = (MessageProducer) session.createProducer(destination); + + _connection.setExceptionListener(this); + + _connection.start(); + + int msgCount = 0; + while (_publish) + { +/* + TextMessage msg = session.createTextMessage( + "Presented to in conjunction with Mahnah Mahnah and the Snowths: " + ++messageNumber); +*/ + ObjectMessage msg = null; + if (_messageSize != 0) + { + msg = TestMessageFactory.newObjectMessage(session, _messageSize); + } + else + { + msg = session.createObjectMessage(); + } + + Long time = System.nanoTime(); + msg.setStringProperty("timestampString", Long.toString(time)); + msg.setLongProperty("timestamp", time); + + ((BasicMessageProducer) producer).send(msg, DeliveryMode.PERSISTENT, true); + + _log.info("Message Sent:" + msgCount++); + _log.debug(msg); + + if (msgCount == Integer.MAX_VALUE) + { + _publish = false; + } + + if (SLEEP_TIME > 0) + { + try + { + Thread.sleep(SLEEP_TIME); + } + catch (InterruptedException ie) + { + //do nothing + } + } + } + + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + + private void createConnection(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException + { + _publish = true; + _connection = new AMQConnection(brokerDetails, "guest", "guest", clientID, virtualpath); + _log.info("Connected with URL:" + _connection.toURL()); + } + + /** + * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank + * means the server will allocate a name. + */ + public static void main(String[] args) + { + if (args.length < 2) + { + System.err.println("Usage: TestPingPublisher [message size in bytes]"); + System.exit(0); + } + try + { + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); + if (args.length > 2 ) + { + _messageSize = Integer.parseInt(args[2]); + } + new TestPingPublisher(args[0], clientID, args[1]); + } + catch (UnknownHostException e) + { + e.printStackTrace(); + } + catch (AMQException e) + { + System.err.println("Error in client: " + e); + e.printStackTrace(); + } + catch (URLSyntaxException e) + { + System.err.println("Error in connection arguments : " + e); + } + + //System.exit(0); + } + + /** + * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) + */ + public void onException(JMSException e) + { + System.err.println(e.getMessage()); + + _publish = false; + e.printStackTrace(System.err); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java new file mode 100644 index 0000000000..001f1e3568 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java @@ -0,0 +1,134 @@ +/* + * + * 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.qpid.pingpong; + +import org.apache.log4j.Logger; +import org.apache.log4j.Level; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.jms.Session; + +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Topic; +import javax.jms.JMSException; +import java.net.InetAddress; + +public class TestPingSubscriber +{ + private static final Logger _logger = Logger.getLogger(TestPingSubscriber.class); + + private static class TestPingMessageListener implements MessageListener + { + public TestPingMessageListener() + { + } + + long _lastTimestamp = 0L; + long _lastTimestampString = 0L; + + public void onMessage(javax.jms.Message message) + { + Long time = System.nanoTime(); + + if (_logger.isInfoEnabled()) + { + long timestampString = 0L; + + try + { + long timestamp = message.getLongProperty("timestamp"); + timestampString = Long.parseLong(message.getStringProperty("timestampString")); + + if (timestampString != timestamp) + { + _logger.info("Timetamps differ!:\n" + + "timestamp:" + timestamp + "\n" + + "timestampString:" + timestampString); + } + + } + catch (JMSException jmse) + { + // ignore + } + + + long stringDiff = time - timestampString; + + _logger.info("Ping: TS:" + stringDiff / 1000 + "us"); + + // _logger.info(_name + " got message '" + message + "\n"); + } + } + } + + public static void main(String[] args) + { + _logger.info("Starting..."); + + if (args.length < 4) + { + System.out.println("Usage: brokerdetails username password virtual-path [selector] "); + System.exit(1); + } + try + { + InetAddress address = InetAddress.getLocalHost(); + AMQConnection con1 = new AMQConnection(args[0], args[1], args[2], + address.getHostName(), args[3]); + + _logger.info("Connected with URL:" + con1.toURL()); + + final org.apache.qpid.jms.Session session1 = (org.apache.qpid.jms.Session) + con1.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + String selector = null; + + if (args.length == 5) + { + selector = args[4]; + _logger.info("Message selector is <" + selector + ">..."); + } + else + { + _logger.info("Not using message selector "); + } + + Topic t = new AMQTopic("ping"); + + MessageConsumer consumer1 = session1.createConsumer(t, + 1, false, false, selector); + + consumer1.setMessageListener(new TestPingMessageListener()); + con1.start(); + } + catch (Throwable t) + { + System.err.println("Fatal error: " + t); + t.printStackTrace(); + } + + System.out.println("Waiting..."); + } +} + diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingClient.java deleted file mode 100644 index c96f6bd61d..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingClient.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * - * 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.qpid.pingpong; - -import org.apache.log4j.Logger; -import org.apache.log4j.Level; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.jms.Session; - -import javax.jms.*; -import java.net.InetAddress; - -public class TestPingClient -{ - private static final Logger _logger = Logger.getLogger(TestPingClient.class); - - private static class TestPingMessageListener implements MessageListener - { - public TestPingMessageListener() - { - } - - long _lastTimestamp = 0L; - long _lastTimestampString = 0L; - - public void onMessage(javax.jms.Message message) - { - if (_logger.isInfoEnabled()) - { - long timestamp = 0L; - long timestampString = 0L; - - try - { - timestamp = message.getLongProperty("timestamp"); - timestampString = Long.parseLong(message.getStringProperty("timestampString")); - - if (timestampString != timestamp) - { - _logger.info("Timetamps differ!:\n" + - "timestamp:" + timestamp + "\n" + - "timestampString:" + timestampString); - } - - } - catch (JMSException jmse) - { - //ignore - } - - long diff = timestamp - _lastTimestamp; - _lastTimestamp = timestamp; - - long stringDiff = timestampString - _lastTimestampString; - - _lastTimestampString = timestampString; - - _logger.info("Ping: T:" + diff + "ms, TS:" + stringDiff); - - // _logger.info(_name + " got message '" + message + "\n"); - } - } - } - - public static void main(String[] args) - { - _logger.setLevel(Level.INFO); - - _logger.info("Starting..."); - - if (args.length < 4) - { - System.out.println("Usage: brokerdetails username password virtual-path [selector] "); - System.exit(1); - } - try - { - InetAddress address = InetAddress.getLocalHost(); - AMQConnection con1 = new AMQConnection(args[0], args[1], args[2], - address.getHostName(), args[3]); - - - _logger.info("Connected with URL:" + con1.toURL()); - - final org.apache.qpid.jms.Session session1 = (org.apache.qpid.jms.Session) - con1.createSession(false, Session.AUTO_ACKNOWLEDGE); - - - String selector = null; - - if (args.length == 5) - { - selector = args[4]; - _logger.info("Message selector is <" + selector + ">..."); - } - else - { - _logger.info("Not using message selector"); - } - - - Queue q = new AMQQueue("ping"); - - MessageConsumer consumer1 = session1.createConsumer(q, - 1, false, false, selector); - - consumer1.setMessageListener(new TestPingMessageListener()); - con1.start(); - } - catch (Throwable t) - { - System.err.println("Fatal error: " + t); - t.printStackTrace(); - } - - System.out.println("Waiting..."); - } -} - diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingProducer.java deleted file mode 100644 index bb9e17615e..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingProducer.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * - * 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.qpid.pingpong; - -import org.apache.log4j.Logger; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.AMQException; -import org.apache.qpid.url.URLSyntaxException; -import org.apache.qpid.client.AMQNoConsumersException; -import org.apache.qpid.client.BasicMessageProducer; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.message.TestMessageFactory; -import org.apache.qpid.jms.MessageProducer; -import org.apache.qpid.jms.Session; - -import javax.jms.*; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * A client that behaves as follows: - *
    • Connects to a queue, whose name is specified as a cmd-line argument
    • - *
    • Creates a temporary queue
    • - *
    • Creates messages containing a property that is the name of the temporary queue
    • - *
    • Fires off a message on the original queue and waits for a response on the temporary queue
    • - *
    - */ -public class TestPingProducer implements ExceptionListener -{ - private static final Logger _log = Logger.getLogger(TestPingProducer.class); - - private AMQConnection _connection; - - private static int _messageSize = 0; - private boolean _publish; - - private long SLEEP_TIME = 250L; - -// private class CallbackHandler implements MessageListener -// { -// -// private int _actualMessageCount; -// -// -// public void onMessage(Message m) -// { -// if (_log.isDebugEnabled()) -// { -// _log.debug("Message received: " + m); -// } -// _actualMessageCount++; -// if (_actualMessageCount % 1000 == 0) -// { -// _log.info("Received message count: " + _actualMessageCount); -// } -// } -// } - - public TestPingProducer(boolean TRANSACTED, String brokerDetails, String clientID, - String virtualpath) throws AMQException, URLSyntaxException - { - try - { - createConnection(brokerDetails, clientID, virtualpath); - - Session session; - - if (TRANSACTED) - { - session = (Session) _connection.createSession(true, Session.SESSION_TRANSACTED); - } - else - { - session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - String queue = "ping"; - AMQQueue destination = new AMQQueue(queue); - MessageProducer producer = (MessageProducer) session.createProducer(destination); - - _connection.setExceptionListener(this); - - _connection.start(); - - while (_publish) - { -/* - TextMessage msg = session.createTextMessage( - "Presented to in conjunction with Mahnah Mahnah and the Snowths: " + ++messageNumber); -*/ - ObjectMessage msg = null; - if (_messageSize != 0) - { - msg = TestMessageFactory.newObjectMessage(session, _messageSize); - } - else - { - msg = session.createObjectMessage(); - } - - msg.setStringProperty("timestampString", Long.toString(System.currentTimeMillis())); - msg.setLongProperty("timestamp", System.currentTimeMillis()); - - ((BasicMessageProducer) producer).send(msg, DeliveryMode.NON_PERSISTENT, true); - _log.info("Message Sent."); - _log.debug(msg); - - - if (TRANSACTED) - { - try - { - session.commit(); - _log.debug("Session Commited."); - } - catch (JMSException e) - { - _log.trace("JMSException on commit:" + e); - try - { - session.rollback(); - _log.debug("Message rolled back."); - } - catch (JMSException jsme) - { - _log.trace("JMSE on rollback:" + jsme); - } - - - if (e.getLinkedException() instanceof AMQNoConsumersException) - { - _log.info("No Consumers on queue:'" + queue + "'"); - continue; - } - } - } - - - if (SLEEP_TIME > 0) - { - try - { - Thread.sleep(SLEEP_TIME); - } - catch (InterruptedException ie) - { - //do nothing - } - } - - - } - - } - catch (JMSException e) - { - _publish = false; - e.printStackTrace(); - } - } - - private void createConnection(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException - { - _publish = true; - _connection = new AMQConnection(brokerDetails, "guest", "guest", - clientID, virtualpath); - _log.info("Connected with URL:" + _connection.toURL()); - } - - /** - * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank - * means the server will allocate a name. - */ - public static void main(String[] args) - { - if (args.length < 2) - { - System.err.println("Usage: TestPingPublisher [transacted] [message size in bytes]"); - System.exit(0); - } - try - { - InetAddress address = InetAddress.getLocalHost(); - String clientID = address.getHostName() + System.currentTimeMillis(); - boolean transacted = false; - if (args.length == 3 ) - { - transacted = Boolean.parseBoolean(args[2]); - } - else if (args.length > 3 ) - { - transacted = Boolean.parseBoolean(args[2]); - _messageSize = Integer.parseInt(args[3]); - } - - new TestPingProducer(transacted, args[0], clientID, args[1]); - } - catch (UnknownHostException e) - { - e.printStackTrace(); - } - catch (AMQException e) - { - System.err.println("Error in client: " + e); - e.printStackTrace(); - } - catch (URLSyntaxException e) - { - System.err.println("Error in connection arguments : " + e); - } - - //System.exit(0); - } - - /** - * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) - */ - public void onException(JMSException e) - { - System.err.println(e.getMessage()); - - _publish = false; - e.printStackTrace(System.err); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingPublisher.java b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingPublisher.java deleted file mode 100644 index 3b2dcc4d36..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingPublisher.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * - * 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.qpid.pingpong; - -import org.apache.log4j.Logger; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.AMQException; -import org.apache.qpid.url.URLSyntaxException; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.BasicMessageProducer; -import org.apache.qpid.client.message.TestMessageFactory; -import org.apache.qpid.jms.MessageProducer; -import org.apache.qpid.jms.Session; - -import javax.jms.*; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * A client that behaves as follows: - *
    • Connects to a queue, whose name is specified as a cmd-line argument
    • - *
    • Creates a temporary queue
    • - *
    • Creates messages containing a property that is the name of the temporary queue
    • - *
    • Fires off a message on the original queue and waits for a response on the temporary queue
    • - *
    - */ -public class TestPingPublisher implements ExceptionListener -{ - private static final Logger _log = Logger.getLogger(TestPingPublisher.class); - - private AMQConnection _connection; - - private boolean _publish; - private static int _messageSize = 0; - private long SLEEP_TIME = 0L; - -// private class CallbackHandler implements MessageListener -// { -// -// private int _actualMessageCount; -// -// -// public void onMessage(Message m) -// { -// if (_log.isDebugEnabled()) -// { -// _log.debug("Message received: " + m); -// } -// _actualMessageCount++; -// if (_actualMessageCount % 1000 == 0) -// { -// _log.info("Received message count: " + _actualMessageCount); -// } -// } -// } - - public TestPingPublisher(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException - { - try - { - createConnection(brokerDetails, clientID, virtualpath); - - Session session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - //AMQQueue destination = new AMQQueue("ping"); - AMQTopic destination = new AMQTopic("ping"); - MessageProducer producer = (MessageProducer) session.createProducer(destination); - - _connection.setExceptionListener(this); - - _connection.start(); - - int msgCount = 0; - while (_publish) - { -/* - TextMessage msg = session.createTextMessage( - "Presented to in conjunction with Mahnah Mahnah and the Snowths: " + ++messageNumber); -*/ - ObjectMessage msg = null; - if (_messageSize != 0) - { - msg = TestMessageFactory.newObjectMessage(session, _messageSize); - } - else - { - msg = session.createObjectMessage(); - } - - Long time = System.nanoTime(); - msg.setStringProperty("timestampString", Long.toString(time)); - msg.setLongProperty("timestamp", time); - - ((BasicMessageProducer) producer).send(msg, DeliveryMode.PERSISTENT, true); - - _log.info("Message Sent:" + msgCount++); - _log.debug(msg); - - if (msgCount == Integer.MAX_VALUE) - { - _publish = false; - } - - if (SLEEP_TIME > 0) - { - try - { - Thread.sleep(SLEEP_TIME); - } - catch (InterruptedException ie) - { - //do nothing - } - } - } - - } - catch (JMSException e) - { - e.printStackTrace(); - } - } - - private void createConnection(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException - { - _publish = true; - _connection = new AMQConnection(brokerDetails, "guest", "guest", clientID, virtualpath); - _log.info("Connected with URL:" + _connection.toURL()); - } - - /** - * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank - * means the server will allocate a name. - */ - public static void main(String[] args) - { - if (args.length < 2) - { - System.err.println("Usage: TestPingPublisher [message size in bytes]"); - System.exit(0); - } - try - { - InetAddress address = InetAddress.getLocalHost(); - String clientID = address.getHostName() + System.currentTimeMillis(); - if (args.length > 2 ) - { - _messageSize = Integer.parseInt(args[2]); - } - new TestPingPublisher(args[0], clientID, args[1]); - } - catch (UnknownHostException e) - { - e.printStackTrace(); - } - catch (AMQException e) - { - System.err.println("Error in client: " + e); - e.printStackTrace(); - } - catch (URLSyntaxException e) - { - System.err.println("Error in connection arguments : " + e); - } - - //System.exit(0); - } - - /** - * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) - */ - public void onException(JMSException e) - { - System.err.println(e.getMessage()); - - _publish = false; - e.printStackTrace(System.err); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingSubscriber.java b/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingSubscriber.java deleted file mode 100644 index 001f1e3568..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/pingpong/TestPingSubscriber.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * - * 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.qpid.pingpong; - -import org.apache.log4j.Logger; -import org.apache.log4j.Level; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.jms.Session; - -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.Topic; -import javax.jms.JMSException; -import java.net.InetAddress; - -public class TestPingSubscriber -{ - private static final Logger _logger = Logger.getLogger(TestPingSubscriber.class); - - private static class TestPingMessageListener implements MessageListener - { - public TestPingMessageListener() - { - } - - long _lastTimestamp = 0L; - long _lastTimestampString = 0L; - - public void onMessage(javax.jms.Message message) - { - Long time = System.nanoTime(); - - if (_logger.isInfoEnabled()) - { - long timestampString = 0L; - - try - { - long timestamp = message.getLongProperty("timestamp"); - timestampString = Long.parseLong(message.getStringProperty("timestampString")); - - if (timestampString != timestamp) - { - _logger.info("Timetamps differ!:\n" + - "timestamp:" + timestamp + "\n" + - "timestampString:" + timestampString); - } - - } - catch (JMSException jmse) - { - // ignore - } - - - long stringDiff = time - timestampString; - - _logger.info("Ping: TS:" + stringDiff / 1000 + "us"); - - // _logger.info(_name + " got message '" + message + "\n"); - } - } - } - - public static void main(String[] args) - { - _logger.info("Starting..."); - - if (args.length < 4) - { - System.out.println("Usage: brokerdetails username password virtual-path [selector] "); - System.exit(1); - } - try - { - InetAddress address = InetAddress.getLocalHost(); - AMQConnection con1 = new AMQConnection(args[0], args[1], args[2], - address.getHostName(), args[3]); - - _logger.info("Connected with URL:" + con1.toURL()); - - final org.apache.qpid.jms.Session session1 = (org.apache.qpid.jms.Session) - con1.createSession(false, Session.AUTO_ACKNOWLEDGE); - - - String selector = null; - - if (args.length == 5) - { - selector = args[4]; - _logger.info("Message selector is <" + selector + ">..."); - } - else - { - _logger.info("Not using message selector "); - } - - Topic t = new AMQTopic("ping"); - - MessageConsumer consumer1 = session1.createConsumer(t, - 1, false, false, selector); - - consumer1.setMessageListener(new TestPingMessageListener()); - con1.start(); - } - catch (Throwable t) - { - System.err.println("Fatal error: " + t); - t.printStackTrace(); - } - - System.out.println("Waiting..."); - } -} - -- cgit v1.2.1 From 1bd479182fcfa30aad8abf69241e9eac560f6655 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Tue, 16 Jan 2007 16:44:17 +0000 Subject: (Patch submitted by Rupert Smith) Refactored the test ping classes to share common code. Made them runnable from the command line (the same as they already were). Also made it possible to instantiate them in other code more easily. A unit test class has been added that performs a ping. This is so that it can be run with the TKTestRunner to scale it up and take performance measurements. Junit-toolkit added as a dependency to the maven build system. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@496753 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/AbstractPingClient.java | 70 +++++ .../org/apache/qpid/ping/AbstractPingProducer.java | 193 ++++++++++++ .../java/org/apache/qpid/ping/TestPingClient.java | 166 +++++----- .../org/apache/qpid/ping/TestPingProducer.java | 334 ++++++++++----------- .../apache/qpid/requestreply/PingPongClient.java | 175 +++++++++++ .../apache/qpid/requestreply/PingPongProducer.java | 301 +++++++++++++++++++ 6 files changed, 985 insertions(+), 254 deletions(-) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongClient.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java new file mode 100644 index 0000000000..3c1a476d51 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java @@ -0,0 +1,70 @@ +package org.apache.qpid.ping; + +import javax.jms.JMSException; + +import org.apache.log4j.Logger; + +import org.apache.qpid.jms.Session; + +/** + * Provides functionality common to all ping clients. Provides the ability to manage a session and a convenience method + * to commit on the current transaction. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Commit the current transcation. + *
    + * + * @author Rupert Smith + */ +public abstract class AbstractPingClient +{ + private static final Logger _logger = Logger.getLogger(TestPingClient.class); + + /** Used to keep a handle on the JMS session to send replies using. */ + protected Session _session; + + /** + * Creates an abstract ping client to manage the specified transcation. + * + * @param session The session. + */ + public AbstractPingClient(Session session) + { + _session = session; + } + + /** + * Convenience method to commit the transaction on the session associated with this bounce back client. + * + * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + */ + protected void commitTx() throws JMSException + { + if (_session.getTransacted()) + { + try + { + _session.commit(); + _logger.trace("Session Commited."); + } + catch (JMSException e) + { + _logger.trace("JMSException on commit:" + e.getMessage(), e); + + try + { + _session.rollback(); + _logger.debug("Message rolled back."); + } + catch (JMSException jmse) + { + _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); + + // Both commit and rollback failed. Throw the rollback exception. + throw jmse; + } + } + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java new file mode 100644 index 0000000000..e2c2d5b440 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java @@ -0,0 +1,193 @@ +package org.apache.qpid.ping; + +import javax.jms.*; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQNoConsumersException; +import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.jms.Session; + +/** + * This abstract class captures functionality that is common to all ping producers. It provides functionality to + * manage a session, and a convenience method to commit a transaction on the session. It also provides a framework + * for running a ping loop, and terminating that loop on exceptions or a shutdown handler. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Manage session. + *
    Provide clean shutdown on exception or shutdown hook. + *
    Provide useable shutdown hook implementation. + *
    + * + * @author Rupert Smith + */ +public abstract class AbstractPingProducer implements Runnable, ExceptionListener +{ + private static final Logger _logger = Logger.getLogger(AbstractPingProducer.class); + + /** Holds the current Qpid session to send and receive pings on. */ + protected Session _session; + + /** Used to tell the ping loop when to terminate, it only runs while this is true. */ + protected boolean _publish = true; + + /** + * Creates an AbstractPingProducer on a session. + */ + public AbstractPingProducer(Session session) + { + _session = session; + } + + /** + * Generates a test message of the specified size. + * + * @param session The Qpid session under which to generate the message. + * @param replyQueue The reply-to destination for the message. + * @param messageSize The desired size of the message in bytes. + * @param currentTime The timestamp to add to the message as a "timestamp" property. + * + * @return A freshly generated test message. + * + * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. + */ + public static ObjectMessage getTestMessage(Session session, Queue replyQueue, int messageSize, long currentTime, + boolean persistent) throws JMSException + { + ObjectMessage msg; + + if (messageSize != 0) + { + msg = TestMessageFactory.newObjectMessage(session, messageSize); + } + else + { + msg = session.createObjectMessage(); + } + + // Set the messages persistent delivery flag. + msg.setJMSDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + // Timestamp the message. + msg.setLongProperty("timestamp", currentTime); + + // Ensure that the temporary reply queue is set as the reply to destination for the message. + if (replyQueue != null) + { + msg.setJMSReplyTo(replyQueue); + } + + return msg; + } + + /** + * Convenience method for a short pause. + * + * @param sleepTime The time in milliseconds to pause for. + */ + public static void pause(long sleepTime) + { + if (sleepTime > 0) + { + try + { + Thread.sleep(sleepTime); + } + catch (InterruptedException ie) + { } + } + } + + public abstract void pingLoop(); + + /** + * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this + * flag has been cleared. + */ + public void stop() + { + _publish = false; + } + + /** + * Implements a ping loop that repeatedly pings until the publish flag becomes false. + */ + public void run() + { + // Keep running until the publish flag is cleared. + while (_publish) + { + pingLoop(); + } + } + + /** + * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the + * connection, this clears the publish flag which in turn will halt the ping loop. + * + * @param e The exception that triggered this callback method. + */ + public void onException(JMSException e) + { + _publish = false; + _logger.debug("There was a JMSException: " + e.getMessage(), e); + } + + /** + * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered + * with the runtime system as a shutdown hook. + * + * @return A shutdown hook for the ping loop. + */ + public Thread getShutdownHook() + { + return new Thread(new Runnable() + { + public void run() + { + stop(); + } + }); + } + + /** + * Convenience method to commit the transaction on the session associated with this pinger. + * + * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + */ + protected void commitTx() throws JMSException + { + if (_session.getTransacted()) + { + try + { + _session.commit(); + _logger.trace("Session Commited."); + } + catch (JMSException e) + { + _logger.trace("JMSException on commit:" + e.getMessage(), e); + + // Warn that the bounce back client is not available. + if (e.getLinkedException() instanceof AMQNoConsumersException) + { + _logger.debug("No consumers on queue."); + } + + try + { + _session.rollback(); + _logger.trace("Message rolled back."); + } + catch (JMSException jmse) + { + _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); + + // Both commit and rollback failed. Throw the rollback exception. + throw jmse; + } + } + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java index c96f6bd61d..3063e83127 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java @@ -7,9 +7,9 @@ * 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 @@ -18,112 +18,104 @@ * under the License. * */ -package org.apache.qpid.pingpong; +package org.apache.qpid.ping; + +import java.net.InetAddress; + +import javax.jms.*; import org.apache.log4j.Logger; -import org.apache.log4j.Level; + import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.jms.Session; -import javax.jms.*; -import java.net.InetAddress; - -public class TestPingClient +/** + * PingClient is a message listener that received time stamped ping messages. It can work out how long a ping took, + * provided that its clokc is synchronized to that of the ping producer, or by running it on the same machine (or jvm) + * as the ping producer. + * + *

    There is a verbose mode flag which causes information about each ping to be output to the console + * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should + * be disabled for real timing tests as writing to the console will slow things down. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Provide command line invocation to start the ping consumer on a configurable broker url. + *
    + */ +class TestPingClient extends AbstractPingClient implements MessageListener { private static final Logger _logger = Logger.getLogger(TestPingClient.class); - private static class TestPingMessageListener implements MessageListener + /** Used to indicate that the reply generator should log timing info to the console (logger info level). */ + private boolean _verbose = false; + + /** + * Creates a PingPongClient on the specified session. + * + * @param session The JMS Session for the ping pon client to run on. + * @param consumer The message consumer to receive the messages with. + * @param verbose If set to true will output timing information on every message. + */ + public TestPingClient(Session session, MessageConsumer consumer, boolean verbose) throws JMSException { - public TestPingMessageListener() - { - } - - long _lastTimestamp = 0L; - long _lastTimestampString = 0L; - - public void onMessage(javax.jms.Message message) - { - if (_logger.isInfoEnabled()) - { - long timestamp = 0L; - long timestampString = 0L; - - try - { - timestamp = message.getLongProperty("timestamp"); - timestampString = Long.parseLong(message.getStringProperty("timestampString")); - - if (timestampString != timestamp) - { - _logger.info("Timetamps differ!:\n" + - "timestamp:" + timestamp + "\n" + - "timestampString:" + timestampString); - } - - } - catch (JMSException jmse) - { - //ignore - } + // Hang on to the session for the replies. + super(session); - long diff = timestamp - _lastTimestamp; - _lastTimestamp = timestamp; - - long stringDiff = timestampString - _lastTimestampString; - - _lastTimestampString = timestampString; - - _logger.info("Ping: T:" + diff + "ms, TS:" + stringDiff); - - // _logger.info(_name + " got message '" + message + "\n"); - } - } + // Set this up to listen for messages on the queue. + consumer.setMessageListener(this); } + /** + * Starts a stand alone ping-pong client running in verbose mode. + * + * @param args + */ public static void main(String[] args) { - _logger.setLevel(Level.INFO); - _logger.info("Starting..."); + // Display help on the command line. if (args.length < 4) { - System.out.println("Usage: brokerdetails username password virtual-path [selector] "); + System.out.println("Usage: brokerdetails username password virtual-path [transacted] [selector]"); System.exit(1); } + + // Extract all comman line parameters. + String brokerDetails = args[0]; + String username = args[1]; + String password = args[2]; + String virtualpath = args[3]; + boolean transacted = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; + String selector = (args.length == 6) ? args[5] : null; + try { InetAddress address = InetAddress.getLocalHost(); - AMQConnection con1 = new AMQConnection(args[0], args[1], args[2], - address.getHostName(), args[3]); + AMQConnection con1 = new AMQConnection(brokerDetails, username, password, address.getHostName(), virtualpath); _logger.info("Connected with URL:" + con1.toURL()); - - final org.apache.qpid.jms.Session session1 = (org.apache.qpid.jms.Session) - con1.createSession(false, Session.AUTO_ACKNOWLEDGE); - - String selector = null; + // Create a transactional or non-transactional session depending on the command line parameter. + Session session = null; - if (args.length == 5) + if (transacted) { - selector = args[4]; - _logger.info("Message selector is <" + selector + ">..."); + session = (org.apache.qpid.jms.Session) con1.createSession(false, Session.SESSION_TRANSACTED); } - else + else if (!transacted) { - _logger.info("Not using message selector"); + session = (org.apache.qpid.jms.Session) con1.createSession(false, Session.AUTO_ACKNOWLEDGE); } - Queue q = new AMQQueue("ping"); - MessageConsumer consumer1 = session1.createConsumer(q, - 1, false, false, selector); + MessageConsumer consumer = session.createConsumer(q, 1, false, false, selector); + new TestPingClient(session, consumer, true); - consumer1.setMessageListener(new TestPingMessageListener()); con1.start(); } catch (Throwable t) @@ -134,5 +126,35 @@ public class TestPingClient System.out.println("Waiting..."); } -} + /** + * This is a callback method that is notified of all messages for which this has been registered as a message + * listener on a message consumer. + * + * @param message The message that triggered this callback. + */ + public void onMessage(javax.jms.Message message) + { + try + { + // Spew out some timing information if verbose mode is on. + if (_verbose) + { + Long timestamp = message.getLongProperty("timestamp"); + + if (timestamp != null) + { + long diff = System.currentTimeMillis() - timestamp; + _logger.info("Ping time: " + diff); + } + } + + // Commit the transaction if running in transactional mode. + commitTx(); + } + catch (JMSException e) + { + _logger.debug("There was a JMSException: " + e.getMessage(), e); + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java index bb9e17615e..d47650d049 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java @@ -7,9 +7,9 @@ * 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 @@ -18,226 +18,196 @@ * under the License. * */ -package org.apache.qpid.pingpong; +package org.apache.qpid.ping; + +import java.net.InetAddress; + +import javax.jms.*; import org.apache.log4j.Logger; + import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.AMQException; -import org.apache.qpid.url.URLSyntaxException; -import org.apache.qpid.client.AMQNoConsumersException; -import org.apache.qpid.client.BasicMessageProducer; import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; -import javax.jms.*; -import java.net.InetAddress; -import java.net.UnknownHostException; - /** - * A client that behaves as follows: - *

    • Connects to a queue, whose name is specified as a cmd-line argument
    • - *
    • Creates a temporary queue
    • - *
    • Creates messages containing a property that is the name of the temporary queue
    • - *
    • Fires off a message on the original queue and waits for a response on the temporary queue
    • - *
    + * PingProducer is a client that sends timestamped pings to a queue. It is designed to be run from the command line + * as a stand alone test tool, but it may also be fairly easily instantiated by other code by supplying a session and + * configured message producer. + * + *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop + * does all its work through helper methods, so that code wishing to run a ping cycle is not forced to do so + * by starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is + * also registered to terminate the ping loop cleanly. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Provide a ping cycle. + *
    Provide command line invocation to loop the ping cycle on a configurable broker url. + *
    */ -public class TestPingProducer implements ExceptionListener +class TestPingProducer extends AbstractPingProducer { - private static final Logger _log = Logger.getLogger(TestPingProducer.class); - - private AMQConnection _connection; - - private static int _messageSize = 0; - private boolean _publish; - - private long SLEEP_TIME = 250L; - -// private class CallbackHandler implements MessageListener -// { -// -// private int _actualMessageCount; -// -// -// public void onMessage(Message m) -// { -// if (_log.isDebugEnabled()) -// { -// _log.debug("Message received: " + m); -// } -// _actualMessageCount++; -// if (_actualMessageCount % 1000 == 0) -// { -// _log.info("Received message count: " + _actualMessageCount); -// } -// } -// } - - public TestPingProducer(boolean TRANSACTED, String brokerDetails, String clientID, - String virtualpath) throws AMQException, URLSyntaxException - { - try - { - createConnection(brokerDetails, clientID, virtualpath); + private static final Logger _logger = Logger.getLogger(TestPingProducer.class); - Session session; + /** Used to set up a default message size. */ + private static final int DEFAULT_MESSAGE_SIZE = 0; - if (TRANSACTED) - { - session = (Session) _connection.createSession(true, Session.SESSION_TRANSACTED); - } - else - { - session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - } + /** Used to define how long to wait between pings. */ + private static final long SLEEP_TIME = 250; - String queue = "ping"; - AMQQueue destination = new AMQQueue(queue); - MessageProducer producer = (MessageProducer) session.createProducer(destination); + /** Used to define how long to wait before assuming that a ping has timed out. */ + private static final long TIMEOUT = 3000; - _connection.setExceptionListener(this); + /** Holds the name of the queue to send pings on. */ + private static final String PING_QUEUE_NAME = "ping"; + private static TestPingProducer _pingProducer; - _connection.start(); + /** Holds the message producer to send the pings through. */ + private MessageProducer _producer; - while (_publish) - { -/* - TextMessage msg = session.createTextMessage( - "Presented to in conjunction with Mahnah Mahnah and the Snowths: " + ++messageNumber); -*/ - ObjectMessage msg = null; - if (_messageSize != 0) - { - msg = TestMessageFactory.newObjectMessage(session, _messageSize); - } - else - { - msg = session.createObjectMessage(); - } - - msg.setStringProperty("timestampString", Long.toString(System.currentTimeMillis())); - msg.setLongProperty("timestamp", System.currentTimeMillis()); - - ((BasicMessageProducer) producer).send(msg, DeliveryMode.NON_PERSISTENT, true); - _log.info("Message Sent."); - _log.debug(msg); - - - if (TRANSACTED) - { - try - { - session.commit(); - _log.debug("Session Commited."); - } - catch (JMSException e) - { - _log.trace("JMSException on commit:" + e); - try - { - session.rollback(); - _log.debug("Message rolled back."); - } - catch (JMSException jsme) - { - _log.trace("JMSE on rollback:" + jsme); - } - - - if (e.getLinkedException() instanceof AMQNoConsumersException) - { - _log.info("No Consumers on queue:'" + queue + "'"); - continue; - } - } - } - - - if (SLEEP_TIME > 0) - { - try - { - Thread.sleep(SLEEP_TIME); - } - catch (InterruptedException ie) - { - //do nothing - } - } - - - } + /** Determines whether this producer sends persistent messages from the run method. */ + private boolean _persistent; - } - catch (JMSException e) - { - _publish = false; - e.printStackTrace(); - } + /** Holds the message size to send, from the run method. */ + private int _messageSize; + + public TestPingProducer(Session session, MessageProducer producer) throws JMSException + { + super(session); + _producer = producer; } - private void createConnection(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException + public TestPingProducer(Session session, MessageProducer producer, boolean persistent, int messageSize) + throws JMSException { - _publish = true; - _connection = new AMQConnection(brokerDetails, "guest", "guest", - clientID, virtualpath); - _log.info("Connected with URL:" + _connection.toURL()); + this(session, producer); + + _persistent = persistent; + _messageSize = messageSize; } /** - * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank - * means the server will allocate a name. + * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongClient} also needs + * to be started to bounce the pings back again. + * + *

    The command line takes from 2 to 4 arguments: + *

    + *
    brokerDetails The broker connection string. + *
    virtualPath The virtual path. + *
    transacted A boolean flag, telling this client whether or not to use transactions. + *
    size The size of ping messages to use, in bytes. + *
    + * + * @param args The command line arguments as defined above. */ - public static void main(String[] args) + public static void main(String[] args) throws Exception { + // Extract the command line. if (args.length < 2) { - System.err.println("Usage: TestPingPublisher [transacted] [message size in bytes]"); + System.err.println( + "Usage: TestPingPublisher [transacted] [persistent] [message size in bytes]"); System.exit(0); } - try - { - InetAddress address = InetAddress.getLocalHost(); - String clientID = address.getHostName() + System.currentTimeMillis(); - boolean transacted = false; - if (args.length == 3 ) - { - transacted = Boolean.parseBoolean(args[2]); - } - else if (args.length > 3 ) - { - transacted = Boolean.parseBoolean(args[2]); - _messageSize = Integer.parseInt(args[3]); - } - - new TestPingProducer(transacted, args[0], clientID, args[1]); - } - catch (UnknownHostException e) - { - e.printStackTrace(); - } - catch (AMQException e) + + String brokerDetails = args[0]; + String virtualpath = args[1]; + boolean transacted = (args.length >= 3) ? Boolean.parseBoolean(args[2]) : false; + boolean persistent = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; + int messageSize = (args.length >= 5) ? Integer.parseInt(args[4]) : DEFAULT_MESSAGE_SIZE; + + // Create a connection to the broker. + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); + + Connection _connection = new AMQConnection(brokerDetails, "guest", "guest", clientID, virtualpath); + + // Create a transactional or non-transactional session, based on the command line arguments. + Session session; + + if (transacted) { - System.err.println("Error in client: " + e); - e.printStackTrace(); + session = (Session) _connection.createSession(true, Session.SESSION_TRANSACTED); } - catch (URLSyntaxException e) + else { - System.err.println("Error in connection arguments : " + e); + session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); } - //System.exit(0); + // Create a queue to send the pings on. + Queue pingQueue = new AMQQueue(PING_QUEUE_NAME); + MessageProducer producer = (MessageProducer) session.createProducer(pingQueue); + + // Create a ping producer to handle the request/wait/reply cycle. + _pingProducer = new TestPingProducer(session, producer, persistent, messageSize); + + // Start the message consumers running. + _connection.start(); + + // Create a shutdown hook to terminate the ping-pong producer. + Runtime.getRuntime().addShutdownHook(_pingProducer.getShutdownHook()); + + // Start the ping loop running, ensuring that it is registered to listen for exceptions on the connection too. + _connection.setExceptionListener(_pingProducer); + Thread pingThread = new Thread(_pingProducer); + pingThread.run(); + + // Run until the ping loop is terminated. + pingThread.join(); } /** - * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) + * Sends the specified ping message. + * + * @param message The message to send. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ - public void onException(JMSException e) + public void ping(Message message) throws JMSException { - System.err.println(e.getMessage()); + _producer.send(message); + + // Keep the messageId to correlate with the reply. + String messageId = message.getJMSMessageID(); + + // Commit the transaction if running in transactional mode. This must happen now, rather than at the end of + // this method, as the message will not be sent until the transaction is committed. + commitTx(); + } + /** + * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this + * flag has been cleared. + */ + public void stop() + { _publish = false; - e.printStackTrace(System.err); + } + + /** + * The ping loop implementation. This send out pings of the configured size, persistence and transactionality, and + * waits for short pauses in between each. + */ + public void pingLoop() + { + try + { + // Generate a sample message and time stamp it. + ObjectMessage msg = getTestMessage(_session, null, _messageSize, System.currentTimeMillis(), _persistent); + msg.setLongProperty("timestamp", System.currentTimeMillis()); + + // Send the message. + ping(msg); + + // Introduce a short pause if desired. + pause(SLEEP_TIME); + } + catch (JMSException e) + { + _publish = false; + _logger.debug("There was a JMSException: " + e.getMessage(), e); + } } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongClient.java new file mode 100644 index 0000000000..bee75bb1eb --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongClient.java @@ -0,0 +1,175 @@ +/* + * + * 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.qpid.requestreply; + +import java.net.InetAddress; + +import javax.jms.*; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.jms.Session; +import org.apache.qpid.ping.AbstractPingClient; + +/** + * PingPongClient is a message listener the bounces back messages to their reply to destination. This is used to return + * ping messages generated by {@link org.apache.qpid.requestreply.PingPongProducer} but could be used for other purposes too. + * + *

    The message id from the received message is extracted, and placed into the reply as the correlation id. Messages + * are bounced back to the reply-to destination. The original sender of the message has the option to use either a unique + * temporary queue or the correlation id to correlate the original message to the reply. + * + *

    There is a verbose mode flag which causes information about each ping to be output to the console + * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should + * be disabled for real timing tests as writing to the console will slow things down. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Bounce back messages to their reply to destination. + *
    Provide command line invocation to start the bounce back on a configurable broker url. + *
    + * + * @todo Rename this to BounceBackClient or something similar. + */ +public class PingPongClient extends AbstractPingClient implements MessageListener +{ + private static final Logger _logger = Logger.getLogger(PingPongClient.class); + + /** Used to indicate that the reply generator should log timing info to the console (logger info level). */ + private boolean _verbose = false; + + /** + * Creates a PingPongClient on the specified session. + * + * @param session The JMS Session for the ping pon client to run on. + * @param consumer The message consumer to receive the messages with. + * @param verbose If set to true will output timing information on every message. + */ + public PingPongClient(Session session, MessageConsumer consumer, boolean verbose) throws JMSException + { + // Hang on to the session for the replies. + super(session); + + // Set this up to listen for messages on the queue. + consumer.setMessageListener(this); + } + + /** + * Starts a stand alone ping-pong client running in verbose mode. + * + * @param args + */ + public static void main(String[] args) + { + _logger.info("Starting..."); + + // Display help on the command line. + if (args.length < 4) + { + System.out.println("Usage: brokerdetails username password virtual-path [transacted] [selector]"); + System.exit(1); + } + + // Extract all comman line parameters. + String brokerDetails = args[0]; + String username = args[1]; + String password = args[2]; + String virtualpath = args[3]; + boolean transacted = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; + String selector = (args.length == 6) ? args[5] : null; + + try + { + InetAddress address = InetAddress.getLocalHost(); + + AMQConnection con1 = new AMQConnection(brokerDetails, username, password, address.getHostName(), virtualpath); + + _logger.info("Connected with URL:" + con1.toURL()); + + // Create a transactional or non-transactional session depending on the command line parameter. + Session session = null; + + if (transacted) + { + session = (org.apache.qpid.jms.Session) con1.createSession(false, Session.SESSION_TRANSACTED); + } + else if (!transacted) + { + session = (org.apache.qpid.jms.Session) con1.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + Queue q = new AMQQueue("ping"); + + MessageConsumer consumer = session.createConsumer(q, 1, false, false, selector); + new PingPongClient(session, consumer, true); + + con1.start(); + } + catch (Throwable t) + { + System.err.println("Fatal error: " + t); + t.printStackTrace(); + } + + System.out.println("Waiting..."); + } + + /** + * This is a callback method that is notified of all messages for which this has been registered as a message + * listener on a message consumer. It sends a reply (pong) to all messages it receieves on the reply to + * destination of the message. + * + * @param message The message that triggered this callback. + */ + public void onMessage(javax.jms.Message message) + { + try + { + // Spew out some timing information if verbose mode is on. + if (_verbose) + { + Long timestamp = message.getLongProperty("timestamp"); + + if (timestamp != null) + { + long diff = System.currentTimeMillis() - timestamp; + _logger.info("Ping time: " + diff); + } + } + + // Correlate the reply to the original. + message.setJMSCorrelationID(message.getJMSMessageID()); + + // Send the receieved message as the pong reply. + MessageProducer producer = _session.createProducer(message.getJMSReplyTo()); + producer.send(message); + + // Commit the transaction if running in transactional mode. + commitTx(); + } + catch (JMSException e) + { + _logger.debug("There was a JMSException: " + e.getMessage(), e); + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java new file mode 100644 index 0000000000..8bb2da8b6f --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -0,0 +1,301 @@ +/* + * + * 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.qpid.requestreply; + +import java.net.InetAddress; +import java.util.HashMap; +import java.util.Map; + +import javax.jms.*; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQNoConsumersException; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.jms.MessageProducer; +import org.apache.qpid.jms.Session; +import org.apache.qpid.ping.AbstractPingProducer; +import org.apache.qpid.util.concurrent.BooleanLatch; + +/** + * PingPongProducer is a client that sends pings to a queue and waits for pongs to be bounced back by a bounce back + * client (see {@link org.apache.qpid.requestreply.PingPongClient} for the bounce back client). It is designed to be run from the command line + * as a stand alone test tool, but it may also be fairly easily instantiated by other code by supplying a session, + * message producer and message consumer to run the ping-pong cycle on. + * + *

    The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. + * This means that this class has to do some work to correlate pings with pongs; it expectes the original message + * id in the ping to be bounced back in the correlation id. If a new temporary queue per ping were used, then + * this correlation would not need to be done. + * + *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop + * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so + * by starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is + * also registered to terminate the ping-pong loop cleanly. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Provide a ping and wait for response cycle. + *
    Provide command line invocation to loop the ping cycle on a configurable broker url. + *
    + * + * @todo Make temp queue per ping a command line option. + * + * @todo Make the queue name a command line option. + */ +public class PingPongProducer extends AbstractPingProducer implements Runnable, MessageListener, ExceptionListener +{ + private static final Logger _logger = Logger.getLogger(PingPongProducer.class); + + /** Used to set up a default message size. */ + private static final int DEFAULT_MESSAGE_SIZE = 0; + + /** Used to define how long to wait between pings. */ + private static final long SLEEP_TIME = 250; + + /** Used to define how long to wait before assuming that a ping has timed out. */ + private static final long TIMEOUT = 3000; + + /** Holds the name of the queue to send pings on. */ + private static final String PING_QUEUE_NAME = "ping"; + + /** Keeps track of the ping producer instance used in the run loop. */ + private static PingPongProducer _pingProducer; + + /** Holds the message producer to send the pings through. */ + private MessageProducer _producer; + + /** Holds the queue to send the ping replies to. */ + private Queue _replyQueue; + + /** Determines whether this producer sends persistent messages from the run method. */ + private boolean _persistent; + + /** Holds the message size to send, from the run method. */ + private int _messageSize; + + /** Holds a map from message ids to latches on which threads wait for replies. */ + private Map trafficLights = new HashMap(); + + /** Holds a map from message ids to correlated replies. */ + private Map replies = new HashMap(); + + public PingPongProducer(Session session, Queue replyQueue, MessageProducer producer, MessageConsumer consumer) + throws JMSException + { + super(session); + _producer = producer; + _replyQueue = replyQueue; + + consumer.setMessageListener(this); + } + + public PingPongProducer(Session session, Queue replyQueue, MessageProducer producer, MessageConsumer consumer, + boolean persistent, int messageSize) throws JMSException + { + this(session, replyQueue, producer, consumer); + + _persistent = persistent; + _messageSize = messageSize; + } + + /** + * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongClient} also needs + * to be started to bounce the pings back again. + * + *

    The command line takes from 2 to 4 arguments: + *

    + *
    brokerDetails The broker connection string. + *
    virtualPath The virtual path. + *
    transacted A boolean flag, telling this client whether or not to use transactions. + *
    size The size of ping messages to use, in bytes. + *
    + * + * @param args The command line arguments as defined above. + */ + public static void main(String[] args) throws Exception + { + // Extract the command line. + if (args.length < 2) + { + System.err.println( + "Usage: TestPingPublisher [transacted] [persistent] [message size in bytes]"); + System.exit(0); + } + + String brokerDetails = args[0]; + String virtualpath = args[1]; + boolean transacted = (args.length >= 3) ? Boolean.parseBoolean(args[2]) : false; + boolean persistent = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; + int messageSize = (args.length >= 5) ? Integer.parseInt(args[4]) : DEFAULT_MESSAGE_SIZE; + + // Create a connection to the broker. + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); + + Connection _connection = new AMQConnection(brokerDetails, "guest", "guest", clientID, virtualpath); + + // Create a transactional or non-transactional session, based on the command line arguments. + Session session; + + if (transacted) + { + session = (Session) _connection.createSession(true, Session.SESSION_TRANSACTED); + } + else + { + session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + // Create a queue to send the pings on. + Queue pingQueue = new AMQQueue(PING_QUEUE_NAME); + MessageProducer producer = (MessageProducer) session.createProducer(pingQueue); + + // Create a temporary queue to reply with the pongs on. + Queue replyQueue = session.createTemporaryQueue(); + + // Create a message consumer to get the replies with. + MessageConsumer consumer = session.createConsumer(replyQueue); + + // Create a ping producer to handle the request/wait/reply cycle. + _pingProducer = new PingPongProducer(session, replyQueue, producer, consumer, persistent, messageSize); + + // Start the message consumers running. + _connection.start(); + + // Create a shutdown hook to terminate the ping-pong producer. + Runtime.getRuntime().addShutdownHook(_pingProducer.getShutdownHook()); + + // Start the ping loop running, ensuring that it is registered to listen for exceptions on the connection too. + _connection.setExceptionListener(_pingProducer); + Thread pingThread = new Thread(_pingProducer); + pingThread.run(); + + // Run until the ping loop is terminated. + pingThread.join(); + } + + /** + * Stores the received message in the replies map, then resets the boolean latch that a thread waiting for a + * correlating reply may be waiting on. + * + * @param message The received message. + */ + public void onMessage(Message message) + { + try + { + // Store the reply. + String correlationID = message.getJMSCorrelationID(); + replies.put(correlationID, message); + + // Turn the traffic light to green. + BooleanLatch trafficLight = trafficLights.get(correlationID); + + if (trafficLight != null) + { + trafficLight.signal(); + } + else + { + _logger.debug("There was no thread waiting for reply: " + correlationID); + } + } + catch (JMSException e) + { + _logger.warn("There was a JMSException: " + e.getMessage(), e); + } + } + + /** + * Sends the specified ping message and then waits for a correlating reply. If the wait times out before a reply + * arrives, then a null reply is returned from this method. + * + * @param message The message to send. + * @param timeout The timeout in milliseconds. + * + * @return The reply, or null if no reply arrives before the timeout. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + */ + public Message pingAndWaitForReply(Message message, long timeout) throws JMSException + { + _producer.send(message); + + // Keep the messageId to correlate with the reply. + String messageId = message.getJMSMessageID(); + + // Commit the transaction if running in transactional mode. This must happen now, rather than at the end of + // this method, as the message will not be sent until the transaction is committed. + commitTx(); + + // Block the current thread until a reply to the message is received, or it times out. + BooleanLatch trafficLight = new BooleanLatch(); + trafficLights.put(messageId, trafficLight); + + // Note that this call expects a timeout in nanoseconds, millisecond timeout is multiplied up. + trafficLight.await(timeout * 1000); + + // Check the replies to see if one was generated, if not then the reply timed out. + Message result = replies.get(messageId); + + return result; + } + + /** + * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the + * connection, this clears the publish flag which in turn will halt the ping loop. + * + * @param e The exception that triggered this callback method. + */ + public void onException(JMSException e) + { + _publish = false; + _logger.debug("There was a JMSException: " + e.getMessage(), e); + } + + /** + * The ping loop implementation. This send out pings of the configured size, persistence and transactionality, and + * waits for replies and inserts short pauses in between each. + */ + public void pingLoop() + { + try + { + // Generate a sample message and time stamp it. + ObjectMessage msg = getTestMessage(_session, _replyQueue, _messageSize, System.currentTimeMillis(), _persistent); + msg.setLongProperty("timestamp", System.currentTimeMillis()); + + // Send the message and wait for a reply. + pingAndWaitForReply(msg, TIMEOUT); + + // Introduce a short pause if desired. + pause(SLEEP_TIME); + } + catch (JMSException e) + { + _publish = false; + _logger.debug("There was a JMSException: " + e.getMessage(), e); + } + } +} -- cgit v1.2.1 From b4bfefbc739f4738ab63dc8e4596ba7ddd41aa43 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Tue, 16 Jan 2007 19:38:51 +0000 Subject: Fix to broken build due to missing file. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@496833 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongProducer.java | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 8bb2da8b6f..c1d42eeed4 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -20,23 +20,19 @@ */ package org.apache.qpid.requestreply; -import java.net.InetAddress; -import java.util.HashMap; -import java.util.Map; - -import javax.jms.*; - import org.apache.log4j.Logger; - import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQNoConsumersException; import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; import org.apache.qpid.ping.AbstractPingProducer; import org.apache.qpid.util.concurrent.BooleanLatch; +import javax.jms.*; +import java.net.InetAddress; +import java.util.HashMap; +import java.util.Map; + /** * PingPongProducer is a client that sends pings to a queue and waits for pongs to be bounced back by a bounce back * client (see {@link org.apache.qpid.requestreply.PingPongClient} for the bounce back client). It is designed to be run from the command line @@ -238,7 +234,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ - public Message pingAndWaitForReply(Message message, long timeout) throws JMSException + public Message pingAndWaitForReply(Message message, long timeout) throws JMSException, InterruptedException { _producer.send(message); @@ -297,5 +293,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _publish = false; _logger.debug("There was a JMSException: " + e.getMessage(), e); } + catch (InterruptedException e) + { + _publish = false; + _logger.debug("There was an interruption: " + e.getMessage(), e); + } } } -- cgit v1.2.1 From 783b2c2cacd1d1d8a2742223ad91c02e54448f1a Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Wed, 17 Jan 2007 11:16:41 +0000 Subject: added timer for callbackHandler to wait for next message before exiting git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@496991 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/requestreply/ServiceRequestingClient.java | 149 ++++++++++++++++----- 1 file changed, 116 insertions(+), 33 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java index 7d4b5eb24f..27bf8c74ea 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java @@ -40,8 +40,11 @@ import java.net.UnknownHostException; * A client that behaves as follows: *

    • Connects to a queue, whose name is specified as a cmd-line argument
    • *
    • Creates a temporary queue
    • - *
    • Creates messages containing a property that is the name of the temporary queue
    • - *
    • Fires off a message on the original queue and waits for a response on the temporary queue
    • + *
    • Creates messages containing a property(reply-to) that is the name of the temporary queue
    • + *
    • Fires off a message on the original queue and registers the callbackHandler to listen to the response on the temporary queue
    • + *
    • Start the loop to send all messages
    • + *
    • CallbackHandler keeps listening to the responses and exits if all the messages have been received back or + * if the waiting time for next message is elapsed
    • *
    */ public class ServiceRequestingClient implements ExceptionListener @@ -49,6 +52,10 @@ public class ServiceRequestingClient implements ExceptionListener private static final Logger _log = Logger.getLogger(ServiceRequestingClient.class); private long _messageIdentifier = 0; + + // time for which callbackHandler should wait for a message before exiting. Default time= 60 secs + private static long _callbackHandlerWaitingTime = 60000; + private String MESSAGE_DATA; private AMQConnection _connection; @@ -71,20 +78,23 @@ public class ServiceRequestingClient implements ExceptionListener private class CallbackHandler implements MessageListener { - private int _expectedMessageCount; - private int _actualMessageCount; private long _startTime; + // The time when the last message was received by the callbackHandler + private long _messageReceivedTime = 0; + private Object _timerCallbackHandler = new Object(); - public CallbackHandler(int expectedMessageCount, long startTime) + public CallbackHandler(long startTime) { - _expectedMessageCount = expectedMessageCount; _startTime = startTime; + // Start the timer thread, which will keep checking if test should exit because the waiting time has elapsed + (new Thread(new TimerThread())).start(); } public void onMessage(Message m) { + _messageReceivedTime = System.currentTimeMillis(); if (_log.isDebugEnabled()) { _log.debug("Message received: " + m); @@ -95,16 +105,15 @@ public class ServiceRequestingClient implements ExceptionListener if (m.propertyExists("timeSent")) { long timeSent = Long.parseLong(m.getStringProperty("timeSent")); - long now = System.currentTimeMillis(); if (_averageLatency == 0) { - _averageLatency = now - timeSent; + _averageLatency = _messageReceivedTime - timeSent; _log.info("Latency " + _averageLatency); } else { - _log.info("Individual latency: " + (now - timeSent)); - _averageLatency = (_averageLatency + (now - timeSent)) / 2; + _log.info("Individual latency: " + (_messageReceivedTime - timeSent)); + _averageLatency = (_averageLatency + (_messageReceivedTime - timeSent)) / 2; _log.info("Average latency now: " + _averageLatency); } } @@ -124,27 +133,91 @@ public class ServiceRequestingClient implements ExceptionListener } checkForMessageID(m); - if (_actualMessageCount == _expectedMessageCount) + + if (_actualMessageCount == _messageCount) { - _completed = true; - notifyWaiter(); - long timeTaken = System.currentTimeMillis() - _startTime; - _log.info("Total time taken to receive " + _expectedMessageCount + " messages was " + - timeTaken + "ms, equivalent to " + - (_expectedMessageCount / (timeTaken / 1000.0)) + " messages per second"); - - try + finishTesting(_actualMessageCount); + } + } + + /** + * sets completed flag to true, closes the callbackHandler connection and notifies the waiter thread, + * so that the callbackHandler can finish listening for messages. This causes the test to finish. + * @param receivedMessageCount + */ + private void finishTesting(int receivedMessageCount) + { + _completed = true; + notifyWaiter(); + notifyTimerThread(); + + long timeTaken = System.currentTimeMillis() - _startTime; + _log.info("***** Result *****"); + _log.info("Total messages received = " + receivedMessageCount); + _log.info("Total time taken to receive " + receivedMessageCount + " messages was " + + timeTaken + "ms, equivalent to " + + (receivedMessageCount / (timeTaken / 1000.0)) + " messages per second"); + + try + { + _connection.close(); + _log.info("Connection closed"); + } + catch (JMSException e) + { + _log.error("Error closing connection"); + } + } + + private void notifyTimerThread() + { + if (_timerCallbackHandler != null) + { + synchronized (_timerCallbackHandler) { - _connection.close(); - _log.info("Connection closed"); + _timerCallbackHandler.notify(); } - catch (JMSException e) + } + } + + /** + * Thread class implementing the timer for callbackHandler. The thread will exit the test if the waiting time + * has elapsed before next message is received. + */ + private class TimerThread implements Runnable + { + public void run() + { + do { - _log.error("Error closing connection"); + try + { + synchronized(_timerCallbackHandler) + { + _timerCallbackHandler.wait(_callbackHandlerWaitingTime); + } + } + catch (InterruptedException ignore) + { + + } + + // exit if callbackHandler has received all messages + if (_completed) + { + _log.info("timer " + new java.util.Date()); + return; + } } + while ((System.currentTimeMillis() - _messageReceivedTime) < _callbackHandlerWaitingTime); + + // waiting time has elapsed, so exit the test + _log.info(""); + _log.info("Exited after waiting for " + _callbackHandlerWaitingTime/1000 + " secs"); + finishTesting(_actualMessageCount); } } - } + } // end of CallbackHandler class /** * Checks if the received AMQ Message ID(delivery tag) is in sequence, by comparing it with the AMQ MessageID @@ -230,7 +303,7 @@ public class ServiceRequestingClient implements ExceptionListener //now start the clock and the test... final long startTime = System.currentTimeMillis(); - messageConsumer.setMessageListener(new CallbackHandler(messageCount, startTime)); + messageConsumer.setMessageListener(new CallbackHandler(startTime)); } catch (JMSException e) { @@ -284,10 +357,12 @@ public class ServiceRequestingClient implements ExceptionListener */ public static void main(String[] args) { - if (args.length < 6) + if ((args.length < 6) || (args.length == 8)) { - System.err.println( - "Usage: ServiceRequestingClient [] [ ]"); + System.err.println("Usage: ServiceRequestingClient " + + " [] " + + "[ ] " + + "[]"); System.exit(1); } try @@ -296,18 +371,24 @@ public class ServiceRequestingClient implements ExceptionListener boolean transactedMode = false; int deliveryMode = DeliveryMode.NON_PERSISTENT; + if (args.length > 6) + { + messageSize = Integer.parseInt(args[6]); + } if (args.length > 7) { - deliveryMode = args[args.length - 2].toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT + deliveryMode = args[7].toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT; - transactedMode = args[args.length - 1].toUpperCase().charAt(0) == 'T' ? true : false; + transactedMode = args[8].toUpperCase().charAt(0) == 'T' ? true : false; } - if ((args.length == 9) ||(args.length == 7)) + if (args.length > 9) { - messageSize = Integer.parseInt(args[6]); - } + _callbackHandlerWaitingTime = Long.parseLong(args[9]) * 1000; + } + + _log.info("Each message size = " + messageSize + " bytes"); InetAddress address = InetAddress.getLocalHost(); String clientID = address.getHostName() + System.currentTimeMillis(); @@ -316,6 +397,8 @@ public class ServiceRequestingClient implements ExceptionListener messageSize); Object waiter = new Object(); client.run(waiter); + + // Start a thread to synchronized (waiter) { while (!client.isCompleted()) -- cgit v1.2.1 From ab1aa368449bf607fef98f19d19aaceaf4e31cc0 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Wed, 17 Jan 2007 11:24:41 +0000 Subject: git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@496996 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/requestreply/ServiceRequestingClient.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java index 27bf8c74ea..cbdd498b37 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java @@ -205,7 +205,6 @@ public class ServiceRequestingClient implements ExceptionListener // exit if callbackHandler has received all messages if (_completed) { - _log.info("timer " + new java.util.Date()); return; } } @@ -261,8 +260,8 @@ public class ServiceRequestingClient implements ExceptionListener { _isTransactional = transactedMode; - _log.info("Delivery Mode: " + (deliveryMode == DeliveryMode.NON_PERSISTENT ? "Non Persistent" : "Persistent") + - "\t isTransactional: " + _isTransactional); + _log.info("Delivery Mode: " + (deliveryMode == DeliveryMode.NON_PERSISTENT ? "Non Persistent" : "Persistent")); + _log.info("isTransactional: " + _isTransactional); _messageCount = messageCount; MESSAGE_DATA = TestMessageFactory.createMessagePayload(messageDataLength); -- cgit v1.2.1 From f661a2d89c4c79a609a1a29f1ee7f796df69a01e Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 18 Jan 2007 13:11:39 +0000 Subject: (Patch submitted by Rupert Smith) Restructured the ping tests, they now share common base classes to avoid cut and paste coding. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@497425 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/AbstractPingClient.java | 31 +- .../org/apache/qpid/ping/AbstractPingProducer.java | 92 +++--- .../java/org/apache/qpid/ping/TestPingClient.java | 93 +++--- .../org/apache/qpid/ping/TestPingProducer.java | 111 +++---- .../apache/qpid/requestreply/PingPongBouncer.java | 283 ++++++++++++++++++ .../apache/qpid/requestreply/PingPongClient.java | 175 ------------ .../apache/qpid/requestreply/PingPongProducer.java | 318 +++++++++++++++------ 7 files changed, 675 insertions(+), 428 deletions(-) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongClient.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java index 3c1a476d51..7c82710a3f 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java @@ -1,9 +1,13 @@ package org.apache.qpid.ping; +import java.text.SimpleDateFormat; + +import javax.jms.Connection; import javax.jms.JMSException; import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; import org.apache.qpid.jms.Session; /** @@ -19,19 +23,20 @@ import org.apache.qpid.jms.Session; */ public abstract class AbstractPingClient { + /** Used to format time stamping output. */ + protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); + private static final Logger _logger = Logger.getLogger(TestPingClient.class); + private AMQConnection _connection; - /** Used to keep a handle on the JMS session to send replies using. */ - protected Session _session; + public AMQConnection getConnection() + { + return _connection; + } - /** - * Creates an abstract ping client to manage the specified transcation. - * - * @param session The session. - */ - public AbstractPingClient(Session session) + public void setConnection(AMQConnection _connection) { - _session = session; + this._connection = _connection; } /** @@ -39,13 +44,13 @@ public abstract class AbstractPingClient * * @throws javax.jms.JMSException If the commit fails and then the rollback fails. */ - protected void commitTx() throws JMSException + protected void commitTx(Session session) throws JMSException { - if (_session.getTransacted()) + if (session.getTransacted()) { try { - _session.commit(); + session.commit(); _logger.trace("Session Commited."); } catch (JMSException e) @@ -54,7 +59,7 @@ public abstract class AbstractPingClient try { - _session.rollback(); + session.rollback(); _logger.debug("Message rolled back."); } catch (JMSException jmse) diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java index e2c2d5b440..bedd6e3d16 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java @@ -1,5 +1,7 @@ package org.apache.qpid.ping; +import java.text.SimpleDateFormat; + import javax.jms.*; import org.apache.log4j.Logger; @@ -15,9 +17,10 @@ import org.apache.qpid.jms.Session; * *

    *
    CRC Card
    Responsibilities Collaborations - *
    Manage session. + *
    Manage the connection. *
    Provide clean shutdown on exception or shutdown hook. *
    Provide useable shutdown hook implementation. + *
    Run a ping loop. *
    * * @author Rupert Smith @@ -26,51 +29,66 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene { private static final Logger _logger = Logger.getLogger(AbstractPingProducer.class); - /** Holds the current Qpid session to send and receive pings on. */ - protected Session _session; + /** Used to format time stamping output. */ + protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); /** Used to tell the ping loop when to terminate, it only runs while this is true. */ protected boolean _publish = true; + /** Holds the connection handle to the broker. */ + private Connection _connection; + + /** Holds the producer session, need to create test messages. */ + private Session _producerSession; + /** - * Creates an AbstractPingProducer on a session. + * Convenience method for a short pause. + * + * @param sleepTime The time in milliseconds to pause for. */ - public AbstractPingProducer(Session session) + public static void pause(long sleepTime) { - _session = session; + if (sleepTime > 0) + { + try + { + Thread.sleep(sleepTime); + } + catch (InterruptedException ie) + { } + } } + public abstract void pingLoop(); + /** * Generates a test message of the specified size. * - * @param session The Qpid session under which to generate the message. * @param replyQueue The reply-to destination for the message. * @param messageSize The desired size of the message in bytes. - * @param currentTime The timestamp to add to the message as a "timestamp" property. * * @return A freshly generated test message. * * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. */ - public static ObjectMessage getTestMessage(Session session, Queue replyQueue, int messageSize, long currentTime, - boolean persistent) throws JMSException + public ObjectMessage getTestMessage(Queue replyQueue, int messageSize, boolean persistent) throws JMSException { ObjectMessage msg; if (messageSize != 0) { - msg = TestMessageFactory.newObjectMessage(session, messageSize); + msg = TestMessageFactory.newObjectMessage(_producerSession, messageSize); } else { - msg = session.createObjectMessage(); + msg = _producerSession.createObjectMessage(); } // Set the messages persistent delivery flag. msg.setJMSDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); // Timestamp the message. - msg.setLongProperty("timestamp", currentTime); + msg.setLongProperty("timestamp", System.currentTimeMillis()); // Ensure that the temporary reply queue is set as the reply to destination for the message. if (replyQueue != null) @@ -81,26 +99,6 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene return msg; } - /** - * Convenience method for a short pause. - * - * @param sleepTime The time in milliseconds to pause for. - */ - public static void pause(long sleepTime) - { - if (sleepTime > 0) - { - try - { - Thread.sleep(sleepTime); - } - catch (InterruptedException ie) - { } - } - } - - public abstract void pingLoop(); - /** * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this * flag has been cleared. @@ -151,18 +149,38 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene }); } + public Connection getConnection() + { + return _connection; + } + + public void setConnection(Connection connection) + { + this._connection = connection; + } + + public Session getProducerSession() + { + return _producerSession; + } + + public void setProducerSession(Session session) + { + this._producerSession = session; + } + /** * Convenience method to commit the transaction on the session associated with this pinger. * * @throws javax.jms.JMSException If the commit fails and then the rollback fails. */ - protected void commitTx() throws JMSException + protected void commitTx(Session session) throws JMSException { - if (_session.getTransacted()) + if (session.getTransacted()) { try { - _session.commit(); + session.commit(); _logger.trace("Session Commited."); } catch (JMSException e) @@ -177,7 +195,7 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene try { - _session.rollback(); + session.rollback(); _logger.trace("Message rolled back."); } catch (JMSException jmse) diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java index 3063e83127..db89b0d38a 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java @@ -43,6 +43,8 @@ import org.apache.qpid.jms.Session; * Responsibilities Collaborations * Provide command line invocation to start the ping consumer on a configurable broker url. * + * + * @todo Add a better command line interpreter to the main method. The command line is not very nice... */ class TestPingClient extends AbstractPingClient implements MessageListener { @@ -51,20 +53,42 @@ class TestPingClient extends AbstractPingClient implements MessageListener /** Used to indicate that the reply generator should log timing info to the console (logger info level). */ private boolean _verbose = false; + /** The producer session. */ + private Session _consumerSession; + /** - * Creates a PingPongClient on the specified session. + * Creates a TestPingClient on the specified session. + * + * @param brokerDetails + * @param username + * @param password + * @param queueName + * @param virtualpath + * @param transacted + * @param selector + * @param verbose * - * @param session The JMS Session for the ping pon client to run on. - * @param consumer The message consumer to receive the messages with. - * @param verbose If set to true will output timing information on every message. + * @throws Exception All underlying exceptions allowed to fall through. This is only test code... */ - public TestPingClient(Session session, MessageConsumer consumer, boolean verbose) throws JMSException + public TestPingClient(String brokerDetails, String username, String password, String queueName, String virtualpath, + boolean transacted, String selector, boolean verbose) throws Exception { - // Hang on to the session for the replies. - super(session); + // Create a connection to the broker. + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); - // Set this up to listen for messages on the queue. + setConnection(new AMQConnection(brokerDetails, username, password, clientID, virtualpath)); + + // Create a transactional or non-transactional session depending on the command line parameter. + _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + + // Connect a consumer to the ping queue and register this to be called back by it. + Queue q = new AMQQueue(queueName); + MessageConsumer consumer = _consumerSession.createConsumer(q, 1, false, false, selector); consumer.setMessageListener(this); + + // Hang on to the verbose flag setting. + _verbose = verbose; } /** @@ -72,57 +96,32 @@ class TestPingClient extends AbstractPingClient implements MessageListener * * @param args */ - public static void main(String[] args) + public static void main(String[] args) throws Exception { _logger.info("Starting..."); // Display help on the command line. if (args.length < 4) { - System.out.println("Usage: brokerdetails username password virtual-path [transacted] [selector]"); + System.out.println( + "Usage: brokerdetails username password virtual-path [queueName] [verbose] [transacted] [selector]"); System.exit(1); } - // Extract all comman line parameters. + // Extract all command line parameters. String brokerDetails = args[0]; String username = args[1]; String password = args[2]; String virtualpath = args[3]; - boolean transacted = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; - String selector = (args.length == 6) ? args[5] : null; - - try - { - InetAddress address = InetAddress.getLocalHost(); - - AMQConnection con1 = new AMQConnection(brokerDetails, username, password, address.getHostName(), virtualpath); - - _logger.info("Connected with URL:" + con1.toURL()); + String queueName = (args.length >= 5) ? args[4] : "ping"; + boolean verbose = (args.length >= 6) ? Boolean.parseBoolean(args[5]) : true; + boolean transacted = (args.length >= 7) ? Boolean.parseBoolean(args[6]) : false; + String selector = (args.length == 8) ? args[7] : null; - // Create a transactional or non-transactional session depending on the command line parameter. - Session session = null; - - if (transacted) - { - session = (org.apache.qpid.jms.Session) con1.createSession(false, Session.SESSION_TRANSACTED); - } - else if (!transacted) - { - session = (org.apache.qpid.jms.Session) con1.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - Queue q = new AMQQueue("ping"); - - MessageConsumer consumer = session.createConsumer(q, 1, false, false, selector); - new TestPingClient(session, consumer, true); - - con1.start(); - } - catch (Throwable t) - { - System.err.println("Fatal error: " + t); - t.printStackTrace(); - } + // Create the test ping client and set it running. + TestPingClient pingClient = + new TestPingClient(brokerDetails, username, password, queueName, virtualpath, transacted, selector, verbose); + pingClient.getConnection().start(); System.out.println("Waiting..."); } @@ -145,12 +144,12 @@ class TestPingClient extends AbstractPingClient implements MessageListener if (timestamp != null) { long diff = System.currentTimeMillis() - timestamp; - _logger.info("Ping time: " + diff); + System.out.println("Ping time: " + diff); } } // Commit the transaction if running in transactional mode. - commitTx(); + commitTx(_consumerSession); } catch (JMSException e) { diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java index d47650d049..182a6228b1 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java @@ -21,6 +21,8 @@ package org.apache.qpid.ping; import java.net.InetAddress; +import java.text.SimpleDateFormat; +import java.util.Date; import javax.jms.*; @@ -57,49 +59,49 @@ class TestPingProducer extends AbstractPingProducer /** Used to define how long to wait between pings. */ private static final long SLEEP_TIME = 250; - /** Used to define how long to wait before assuming that a ping has timed out. */ - private static final long TIMEOUT = 3000; - /** Holds the name of the queue to send pings on. */ private static final String PING_QUEUE_NAME = "ping"; + private static TestPingProducer _pingProducer; /** Holds the message producer to send the pings through. */ private MessageProducer _producer; /** Determines whether this producer sends persistent messages from the run method. */ - private boolean _persistent; + private boolean _persistent = false; /** Holds the message size to send, from the run method. */ - private int _messageSize; + private int _messageSize = DEFAULT_MESSAGE_SIZE; - public TestPingProducer(Session session, MessageProducer producer) throws JMSException - { - super(session); - _producer = producer; - } + /** Used to indicate that the ping loop should print out whenever it pings. */ + private boolean _verbose = false; - public TestPingProducer(Session session, MessageProducer producer, boolean persistent, int messageSize) - throws JMSException + public TestPingProducer(String brokerDetails, String username, String password, String virtualpath, String queueName, + boolean transacted, boolean persistent, int messageSize, boolean verbose) throws Exception { - this(session, producer); + // Create a connection to the broker. + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); + + setConnection(new AMQConnection(brokerDetails, username, password, clientID, virtualpath)); + + // Create a transactional or non-transactional session, based on the command line arguments. + setProducerSession((Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE)); + + // Create a queue to send the pings on. + Queue pingQueue = new AMQQueue(queueName); + _producer = (MessageProducer) getProducerSession().createProducer(pingQueue); _persistent = persistent; _messageSize = messageSize; + + _verbose = verbose; } /** - * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongClient} also needs + * Starts a ping-pong loop running from the command line. The bounce back client {@link TestPingClient} also needs * to be started to bounce the pings back again. * - *

    The command line takes from 2 to 4 arguments: - *

    - *
    brokerDetails The broker connection string. - *
    virtualPath The virtual path. - *
    transacted A boolean flag, telling this client whether or not to use transactions. - *
    size The size of ping messages to use, in bytes. - *
    - * * @param args The command line arguments as defined above. */ public static void main(String[] args) throws Exception @@ -108,53 +110,33 @@ class TestPingProducer extends AbstractPingProducer if (args.length < 2) { System.err.println( - "Usage: TestPingPublisher [transacted] [persistent] [message size in bytes]"); + "Usage: TestPingPublisher [verbose] [transacted] [persistent] [message size in bytes]"); System.exit(0); } String brokerDetails = args[0]; String virtualpath = args[1]; - boolean transacted = (args.length >= 3) ? Boolean.parseBoolean(args[2]) : false; - boolean persistent = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; - int messageSize = (args.length >= 5) ? Integer.parseInt(args[4]) : DEFAULT_MESSAGE_SIZE; + boolean verbose = (args.length >= 3) ? Boolean.parseBoolean(args[2]) : true; + boolean transacted = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; + boolean persistent = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; + int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; - // Create a connection to the broker. - InetAddress address = InetAddress.getLocalHost(); - String clientID = address.getHostName() + System.currentTimeMillis(); + // Create a ping producer to generate the pings. + _pingProducer = new TestPingProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, transacted, + persistent, messageSize, verbose); - Connection _connection = new AMQConnection(brokerDetails, "guest", "guest", clientID, virtualpath); - - // Create a transactional or non-transactional session, based on the command line arguments. - Session session; - - if (transacted) - { - session = (Session) _connection.createSession(true, Session.SESSION_TRANSACTED); - } - else - { - session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - // Create a queue to send the pings on. - Queue pingQueue = new AMQQueue(PING_QUEUE_NAME); - MessageProducer producer = (MessageProducer) session.createProducer(pingQueue); - - // Create a ping producer to handle the request/wait/reply cycle. - _pingProducer = new TestPingProducer(session, producer, persistent, messageSize); - - // Start the message consumers running. - _connection.start(); + // Start the connection running. + _pingProducer.getConnection().start(); // Create a shutdown hook to terminate the ping-pong producer. Runtime.getRuntime().addShutdownHook(_pingProducer.getShutdownHook()); - // Start the ping loop running, ensuring that it is registered to listen for exceptions on the connection too. - _connection.setExceptionListener(_pingProducer); + // Ensure the ping loop execption listener is registered on the connection to terminate it on error. + _pingProducer.getConnection().setExceptionListener(_pingProducer); + + // Start the ping loop running until it is interrupted. Thread pingThread = new Thread(_pingProducer); pingThread.run(); - - // Run until the ping loop is terminated. pingThread.join(); } @@ -174,16 +156,7 @@ class TestPingProducer extends AbstractPingProducer // Commit the transaction if running in transactional mode. This must happen now, rather than at the end of // this method, as the message will not be sent until the transaction is committed. - commitTx(); - } - - /** - * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this - * flag has been cleared. - */ - public void stop() - { - _publish = false; + commitTx(getProducerSession()); } /** @@ -195,12 +168,16 @@ class TestPingProducer extends AbstractPingProducer try { // Generate a sample message and time stamp it. - ObjectMessage msg = getTestMessage(_session, null, _messageSize, System.currentTimeMillis(), _persistent); + ObjectMessage msg = getTestMessage(null, _messageSize, _persistent); msg.setLongProperty("timestamp", System.currentTimeMillis()); // Send the message. ping(msg); + if (_verbose) + { + System.out.println("Pinged at: " + timestampFormatter.format(new Date())); //" + " with id: " + msg.getJMSMessageID()); + } // Introduce a short pause if desired. pause(SLEEP_TIME); } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java new file mode 100644 index 0000000000..d2a376fff0 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -0,0 +1,283 @@ +/* + * + * 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.qpid.requestreply; + +import java.net.InetAddress; +import java.util.Date; + +import javax.jms.*; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.jms.ConnectionListener; +import org.apache.qpid.jms.Session; +import org.apache.qpid.ping.AbstractPingClient; + +/** + * PingPongBouncer is a message listener the bounces back messages to their reply to destination. This is used to return + * ping messages generated by {@link org.apache.qpid.requestreply.PingPongProducer} but could be used for other purposes + * too. + * + *

    The message id from the received message is extracted, and placed into the reply as the correlation id. Messages + * are bounced back to the reply-to destination. The original sender of the message has the option to use either a unique + * temporary queue or the correlation id to correlate the original message to the reply. + * + *

    There is a verbose mode flag which causes information about each ping to be output to the console + * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should + * be disabled for real timing tests as writing to the console will slow things down. + * + *

    When the a message is received, a reply to producer is created for it if it is not the same as the previous + * message. All subsequent replies are sent using that producer until a different reply to destination is + * encountered; effectively a last used cache of size 1. Fast because it saves creating the reply producer over and + * over again when the destination does not change. For a larger fixed set of reply to destinations could turn this + * into a cache with more elements. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Bounce back messages to their reply to destination. + *
    Provide command line invocation to start the bounce back on a configurable broker url. + *
    + * + * @todo Replace the command line parsing with a neater tool. + * + * @todo Make verbose accept a number of messages, only prints to console every X messages. + */ +public class PingPongBouncer extends AbstractPingClient implements MessageListener +{ + private static final Logger _logger = Logger.getLogger(PingPongBouncer.class); + + /** The default prefetch size for the message consumer. */ + private static final int PREFETCH = 1; + + /** The default no local flag for the message consumer. */ + private static final boolean NO_LOCAL = true; + + /** The default exclusive flag for the message consumer. */ + private static final boolean EXCLUSIVE = false; + + /** Used to indicate that the reply generator should log timing info to the console (logger info level). */ + private boolean _verbose = false; + + /** Determines whether this bounce back client bounces back messages persistently. */ + private boolean _persistent = false; + + /** Keeps track of the response destination of the previous message for the last reply to producer cache. */ + private Destination _lastResponseDest; + + /** The cached, most recently used reply producer. */ + private MessageProducer _cachedReplyProducer; + + /** The consumer session. */ + private Session _consumerSession; + + /** The producer session. */ + private Session _producerSession; + + /** + * Creates a PingPongBouncer on the specified producer and consumer sessions. + * + * @param brokerDetails + * @param username + * @param password + * @param virtualpath + * @param queueName + * @param persistent + * @param transacted + * @param selector + * @param verbose + * @throws JMSException + * + * @throws Exception All underlying exceptions allowed to fall through. This is only test code... + */ + public PingPongBouncer(String brokerDetails, String username, String password, String virtualpath, String queueName, + boolean persistent, boolean transacted, String selector, boolean verbose) throws Exception + { + // Create a client id to uniquely identify this client. + InetAddress address = InetAddress.getLocalHost(); + String clientId = address.getHostName() + System.currentTimeMillis(); + + // Connect to the broker. + setConnection(new AMQConnection(brokerDetails, username, password, clientId, virtualpath)); + _logger.info("Connected with URL:" + getConnection().toURL()); + + // Set up the failover notifier. + getConnection().setConnectionListener(new FailoverNotifier()); + + // Create a session to listen for messages on and one to send replies on, transactional depending on the + // command line option. + Session consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + Session producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + + // Create the queue to listen for message on. + Queue q = new AMQQueue(queueName); + MessageConsumer consumer = consumerSession.createConsumer(q, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); + + // Hang on to the sessions for the messages and replies. + _consumerSession = consumerSession; + _producerSession = producerSession; + + _verbose = verbose; + _persistent = persistent; + + // Set this up to listen for messages on the queue. + consumer.setMessageListener(this); + } + + /** + * Starts a stand alone ping-pong client running in verbose mode. + * + * @param args + */ + public static void main(String[] args) throws Exception + { + System.out.println("Starting..."); + + // Display help on the command line. + if (args.length < 5) + { + System.err.println("Usage: " + + "[ ] [selector]"); + System.exit(1); + } + + // Extract all command line parameters. + String brokerDetails = args[0]; + String username = args[1]; + String password = args[2]; + String virtualpath = args[3]; + String queueName = args[4]; + boolean persistent = ((args.length >= 6) && (args[5].toUpperCase().charAt(0) == 'P')); + boolean transacted = ((args.length >= 7) && (args[6].toUpperCase().charAt(0) == 'T')); + String selector = (args.length == 8) ? args[5] : null; + + // Instantiate the ping pong client with the command line options and start it running. + PingPongBouncer pingBouncer = + new PingPongBouncer(brokerDetails, username, password, virtualpath, queueName, persistent, transacted, selector, + true); + pingBouncer.getConnection().start(); + + System.out.println("Waiting..."); + } + + /** + * This is a callback method that is notified of all messages for which this has been registered as a message + * listener on a message consumer. It sends a reply (pong) to all messages it receieves on the reply to + * destination of the message. + * + * @param message The message that triggered this callback. + */ + public void onMessage(Message message) + { + try + { + String messageCorrelationId = message.getJMSCorrelationID(); + + if (_verbose) + { + _logger.info(timestampFormatter.format(new Date()) + ": Got ping with correlation id, " + + messageCorrelationId); + } + + // Get the reply to destination from the message and check it is set. + Destination responseDest = message.getJMSReplyTo(); + + if (responseDest == null) + { + _logger.debug("Producer not created because the response destination is null."); + + return; + } + + // Check if the reply to destination is different to the last message and create a new producer if so. + if (!responseDest.equals(_lastResponseDest)) + { + _lastResponseDest = responseDest; + + _logger.debug("About to create a producer."); + _cachedReplyProducer = _producerSession.createProducer(responseDest); + _cachedReplyProducer.setDisableMessageTimestamp(true); + _cachedReplyProducer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + _logger.debug("After create a producer."); + } + + // Spew out some timing information if verbose mode is on. + if (_verbose) + { + Long timestamp = message.getLongProperty("timestamp"); + + if (timestamp != null) + { + long diff = System.currentTimeMillis() - timestamp; + _logger.info("Time to bounce point: " + diff); + } + } + + // Correlate the reply to the original. + message.setJMSCorrelationID(messageCorrelationId); + + // Send the receieved message as the pong reply. + _cachedReplyProducer.send(message); + + if (_verbose) + { + _logger.info(timestampFormatter.format(new Date()) + ": Sent reply with correlation id, " + + messageCorrelationId); + } + + // Commit the transaction if running in transactional mode. + commitTx(_producerSession); + } + catch (JMSException e) + { + _logger.debug("There was a JMSException: " + e.getMessage(), e); + } + } + + /** + * A connection listener that logs out any failover complete events. Could do more interesting things with this + * at some point... + */ + public static class FailoverNotifier implements ConnectionListener + { + public void bytesSent(long count) + { } + + public void bytesReceived(long count) + { } + + public boolean preFailover(boolean redirect) + { + return true; + } + + public boolean preResubscribe() + { + return true; + } + + public void failoverComplete() + { + _logger.info("App got failover complete callback."); + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongClient.java deleted file mode 100644 index bee75bb1eb..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongClient.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * - * 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.qpid.requestreply; - -import java.net.InetAddress; - -import javax.jms.*; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.jms.Session; -import org.apache.qpid.ping.AbstractPingClient; - -/** - * PingPongClient is a message listener the bounces back messages to their reply to destination. This is used to return - * ping messages generated by {@link org.apache.qpid.requestreply.PingPongProducer} but could be used for other purposes too. - * - *

    The message id from the received message is extracted, and placed into the reply as the correlation id. Messages - * are bounced back to the reply-to destination. The original sender of the message has the option to use either a unique - * temporary queue or the correlation id to correlate the original message to the reply. - * - *

    There is a verbose mode flag which causes information about each ping to be output to the console - * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should - * be disabled for real timing tests as writing to the console will slow things down. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Bounce back messages to their reply to destination. - *
    Provide command line invocation to start the bounce back on a configurable broker url. - *
    - * - * @todo Rename this to BounceBackClient or something similar. - */ -public class PingPongClient extends AbstractPingClient implements MessageListener -{ - private static final Logger _logger = Logger.getLogger(PingPongClient.class); - - /** Used to indicate that the reply generator should log timing info to the console (logger info level). */ - private boolean _verbose = false; - - /** - * Creates a PingPongClient on the specified session. - * - * @param session The JMS Session for the ping pon client to run on. - * @param consumer The message consumer to receive the messages with. - * @param verbose If set to true will output timing information on every message. - */ - public PingPongClient(Session session, MessageConsumer consumer, boolean verbose) throws JMSException - { - // Hang on to the session for the replies. - super(session); - - // Set this up to listen for messages on the queue. - consumer.setMessageListener(this); - } - - /** - * Starts a stand alone ping-pong client running in verbose mode. - * - * @param args - */ - public static void main(String[] args) - { - _logger.info("Starting..."); - - // Display help on the command line. - if (args.length < 4) - { - System.out.println("Usage: brokerdetails username password virtual-path [transacted] [selector]"); - System.exit(1); - } - - // Extract all comman line parameters. - String brokerDetails = args[0]; - String username = args[1]; - String password = args[2]; - String virtualpath = args[3]; - boolean transacted = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; - String selector = (args.length == 6) ? args[5] : null; - - try - { - InetAddress address = InetAddress.getLocalHost(); - - AMQConnection con1 = new AMQConnection(brokerDetails, username, password, address.getHostName(), virtualpath); - - _logger.info("Connected with URL:" + con1.toURL()); - - // Create a transactional or non-transactional session depending on the command line parameter. - Session session = null; - - if (transacted) - { - session = (org.apache.qpid.jms.Session) con1.createSession(false, Session.SESSION_TRANSACTED); - } - else if (!transacted) - { - session = (org.apache.qpid.jms.Session) con1.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - Queue q = new AMQQueue("ping"); - - MessageConsumer consumer = session.createConsumer(q, 1, false, false, selector); - new PingPongClient(session, consumer, true); - - con1.start(); - } - catch (Throwable t) - { - System.err.println("Fatal error: " + t); - t.printStackTrace(); - } - - System.out.println("Waiting..."); - } - - /** - * This is a callback method that is notified of all messages for which this has been registered as a message - * listener on a message consumer. It sends a reply (pong) to all messages it receieves on the reply to - * destination of the message. - * - * @param message The message that triggered this callback. - */ - public void onMessage(javax.jms.Message message) - { - try - { - // Spew out some timing information if verbose mode is on. - if (_verbose) - { - Long timestamp = message.getLongProperty("timestamp"); - - if (timestamp != null) - { - long diff = System.currentTimeMillis() - timestamp; - _logger.info("Ping time: " + diff); - } - } - - // Correlate the reply to the original. - message.setJMSCorrelationID(message.getJMSMessageID()); - - // Send the receieved message as the pong reply. - MessageProducer producer = _session.createProducer(message.getJMSReplyTo()); - producer.send(message); - - // Commit the transaction if running in transactional mode. - commitTx(); - } - catch (JMSException e) - { - _logger.debug("There was a JMSException: " + e.getMessage(), e); - } - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index c1d42eeed4..6956187b66 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -20,22 +20,28 @@ */ package org.apache.qpid.requestreply; +import java.net.InetAddress; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.*; + import org.apache.log4j.Logger; + import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.jms.ConnectionListener; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; import org.apache.qpid.ping.AbstractPingProducer; -import org.apache.qpid.util.concurrent.BooleanLatch; - -import javax.jms.*; -import java.net.InetAddress; -import java.util.HashMap; -import java.util.Map; /** * PingPongProducer is a client that sends pings to a queue and waits for pongs to be bounced back by a bounce back - * client (see {@link org.apache.qpid.requestreply.PingPongClient} for the bounce back client). It is designed to be run from the command line + * client (see {@link PingPongBouncer} for the bounce back client). It is designed to be run from the command line * as a stand alone test tool, but it may also be fairly easily instantiated by other code by supplying a session, * message producer and message consumer to run the ping-pong cycle on. * @@ -75,8 +81,20 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, /** Holds the name of the queue to send pings on. */ private static final String PING_QUEUE_NAME = "ping"; + /** The batch size. */ + private static final int BATCH_SIZE = 100; + /** Keeps track of the ping producer instance used in the run loop. */ private static PingPongProducer _pingProducer; + private static final int PREFETCH = 100; + private static final boolean NO_LOCAL = true; + private static final boolean EXCLUSIVE = false; + + /** The number of priming loops to run. */ + private static final int PRIMING_LOOPS = 3; + + /** A source for providing sequential unique correlation ids. */ + private AtomicLong idGenerator = new AtomicLong(0L); /** Holds the message producer to send the pings through. */ private MessageProducer _producer; @@ -91,32 +109,65 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, private int _messageSize; /** Holds a map from message ids to latches on which threads wait for replies. */ - private Map trafficLights = new HashMap(); + private Map trafficLights = new HashMap(); + + /** Used to indicate that the ping loop should print out whenever it pings. */ + private boolean _verbose = false; - /** Holds a map from message ids to correlated replies. */ - private Map replies = new HashMap(); + private Session _consumerSession; - public PingPongProducer(Session session, Queue replyQueue, MessageProducer producer, MessageConsumer consumer) - throws JMSException + /** + * Creates a ping pong producer with the specified connection details and type. + * + * @param brokerDetails + * @param username + * @param password + * @param virtualpath + * @param transacted + * @param persistent + * @param messageSize + * @param verbose + * + * @throws Exception All allowed to fall through. This is only test code... + */ + public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, String queueName, + String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose) + throws Exception { - super(session); - _producer = producer; - _replyQueue = replyQueue; + // Create a connection to the broker. + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); + + setConnection(new AMQConnection(brokerDetails, username, password, clientID, virtualpath)); + + // Create transactional or non-transactional sessions, based on the command line arguments. + setProducerSession((Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE)); + _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + // Create a queue and producer to send the pings on. + Queue pingQueue = new AMQQueue(queueName); + _producer = (MessageProducer) getProducerSession().createProducer(pingQueue); + _producer.setDisableMessageTimestamp(true); + _producer.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + // Create a temporary queue to get the pongs on. + _replyQueue = _consumerSession.createTemporaryQueue(); + + // Create a message consumer to get the replies with and register this to be called back by it. + MessageConsumer consumer = _consumerSession.createConsumer(_replyQueue, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); consumer.setMessageListener(this); - } - public PingPongProducer(Session session, Queue replyQueue, MessageProducer producer, MessageConsumer consumer, - boolean persistent, int messageSize) throws JMSException - { - this(session, replyQueue, producer, consumer); + // Run a few priming pings to remove warm up time from test results. + prime(PRIMING_LOOPS); _persistent = persistent; _messageSize = messageSize; + + _verbose = verbose; } /** - * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongClient} also needs + * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs * to be started to bounce the pings back again. * *

    The command line takes from 2 to 4 arguments: @@ -141,59 +192,59 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, String brokerDetails = args[0]; String virtualpath = args[1]; - boolean transacted = (args.length >= 3) ? Boolean.parseBoolean(args[2]) : false; - boolean persistent = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; - int messageSize = (args.length >= 5) ? Integer.parseInt(args[4]) : DEFAULT_MESSAGE_SIZE; - - // Create a connection to the broker. - InetAddress address = InetAddress.getLocalHost(); - String clientID = address.getHostName() + System.currentTimeMillis(); - - Connection _connection = new AMQConnection(brokerDetails, "guest", "guest", clientID, virtualpath); - - // Create a transactional or non-transactional session, based on the command line arguments. - Session session; - - if (transacted) - { - session = (Session) _connection.createSession(true, Session.SESSION_TRANSACTED); - } - else - { - session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - // Create a queue to send the pings on. - Queue pingQueue = new AMQQueue(PING_QUEUE_NAME); - MessageProducer producer = (MessageProducer) session.createProducer(pingQueue); - - // Create a temporary queue to reply with the pongs on. - Queue replyQueue = session.createTemporaryQueue(); - - // Create a message consumer to get the replies with. - MessageConsumer consumer = session.createConsumer(replyQueue); + boolean verbose = (args.length >= 3) ? Boolean.parseBoolean(args[2]) : true; + boolean transacted = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; + boolean persistent = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; + int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; // Create a ping producer to handle the request/wait/reply cycle. - _pingProducer = new PingPongProducer(session, replyQueue, producer, consumer, persistent, messageSize); - - // Start the message consumers running. - _connection.start(); + _pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, null, transacted, + persistent, messageSize, verbose); + _pingProducer.getConnection().start(); // Create a shutdown hook to terminate the ping-pong producer. Runtime.getRuntime().addShutdownHook(_pingProducer.getShutdownHook()); - // Start the ping loop running, ensuring that it is registered to listen for exceptions on the connection too. - _connection.setExceptionListener(_pingProducer); + // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. + _pingProducer.getConnection().setExceptionListener(_pingProducer); + + // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. Thread pingThread = new Thread(_pingProducer); pingThread.run(); - - // Run until the ping loop is terminated. pingThread.join(); } + /** + * Primes the test loop by sending a few messages, then introducing a short wait. This allows the bounce back client + * on the other end a chance to configure its reply producer on the reply to destination. It is also worth calling + * this a few times, in order to prime the JVMs JIT compilation. + * + * @param x The number of priming loops to run. + * + * @throws JMSException All underlying exceptions are allowed to fall through. + */ + public void prime(int x) throws JMSException + { + for (int i = 0; i < x; i++) + { + // Create and send a small message. + Message first = getTestMessage(_replyQueue, 0, false); + _producer.send(first); + commitTx(getProducerSession()); + + try + { + Thread.sleep(100); + } + catch (InterruptedException ignore) + { } + } + } + /** * Stores the received message in the replies map, then resets the boolean latch that a thread waiting for a - * correlating reply may be waiting on. + * correlating reply may be waiting on. This is only done if the reply has a correlation id that is expected + * in the replies map. * * @param message The received message. */ @@ -201,21 +252,37 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, { try { - // Store the reply. + // Store the reply, if it has a correlation id that is expected. String correlationID = message.getJMSCorrelationID(); - replies.put(correlationID, message); + + if (_verbose) + { + _logger.info(timestampFormatter.format(new Date()) + ": Got reply with correlation id, " + correlationID); + } // Turn the traffic light to green. - BooleanLatch trafficLight = trafficLights.get(correlationID); + CountDownLatch trafficLight = trafficLights.get(correlationID); if (trafficLight != null) { - trafficLight.signal(); + _logger.debug("Reply was expected, decrementing the latch for the id."); + trafficLight.countDown(); } else { _logger.debug("There was no thread waiting for reply: " + correlationID); } + + if (_verbose) + { + Long timestamp = message.getLongProperty("timestamp"); + + if (timestamp != null) + { + long diff = System.currentTimeMillis() - timestamp; + _logger.info("Time for round trip: " + diff); + } + } } catch (JMSException e) { @@ -224,50 +291,90 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } /** - * Sends the specified ping message and then waits for a correlating reply. If the wait times out before a reply - * arrives, then a null reply is returned from this method. + * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out + * before a reply arrives, then a null reply is returned from this method. * - * @param message The message to send. - * @param timeout The timeout in milliseconds. + * @param message The message to send. + * @param numPings The number of ping messages to send. + * @param timeout The timeout in milliseconds. * - * @return The reply, or null if no reply arrives before the timeout. + * @return The number of replies received. This may be less than the number sent if the timeout terminated the + * wait for all prematurely. * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ - public Message pingAndWaitForReply(Message message, long timeout) throws JMSException, InterruptedException + public int pingAndWaitForReply(Message message, int numPings, long timeout) throws JMSException, InterruptedException { - _producer.send(message); + // Put a unique correlation id on the message before sending it. + String messageCorrelationId = Long.toString(idGenerator.incrementAndGet()); + message.setJMSCorrelationID(messageCorrelationId); - // Keep the messageId to correlate with the reply. - String messageId = message.getJMSMessageID(); + for (int i = 0; i < numPings; i++) + { + // Re-timestamp the message. + message.setLongProperty("timestamp", System.currentTimeMillis()); + + _producer.send(message); + } // Commit the transaction if running in transactional mode. This must happen now, rather than at the end of // this method, as the message will not be sent until the transaction is committed. - commitTx(); + commitTx(getProducerSession()); + + // Keep the messageId to correlate with the reply. + //String messageId = message.getJMSMessageID(); + + if (_verbose) + { + _logger.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); + } // Block the current thread until a reply to the message is received, or it times out. - BooleanLatch trafficLight = new BooleanLatch(); - trafficLights.put(messageId, trafficLight); + CountDownLatch trafficLight = new CountDownLatch(numPings); + trafficLights.put(messageCorrelationId, trafficLight); // Note that this call expects a timeout in nanoseconds, millisecond timeout is multiplied up. - trafficLight.await(timeout * 1000); + trafficLight.await(timeout, TimeUnit.MILLISECONDS); - // Check the replies to see if one was generated, if not then the reply timed out. - Message result = replies.get(messageId); + // Work out how many replies were receieved. + int numReplies = numPings - (int) trafficLight.getCount(); - return result; + if ((numReplies < numPings) && _verbose) + { + _logger.info("Timed out before all replies received on id, " + messageCorrelationId); + } + else if (_verbose) + { + _logger.info("Got all replies on id, " + messageCorrelationId); + } + + return numReplies; } /** - * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the - * connection, this clears the publish flag which in turn will halt the ping loop. + * Sends the specified ping message but does not wait for a correlating reply. + * + * @param message The message to send. + * @param numPings The number of pings to send. * - * @param e The exception that triggered this callback method. + * @return The reply, or null if no reply arrives before the timeout. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ - public void onException(JMSException e) + public void pingNoWaitForReply(Message message, int numPings) throws JMSException, InterruptedException { - _publish = false; - _logger.debug("There was a JMSException: " + e.getMessage(), e); + for (int i = 0; i < numPings; i++) + { + _producer.send(message); + + if (_verbose) + { + _logger.info(timestampFormatter.format(new Date()) + ": Pinged at."); + } + } + + // Commit the transaction if running in transactional mode, to force the send now. + commitTx(getProducerSession()); } /** @@ -279,11 +386,11 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, try { // Generate a sample message and time stamp it. - ObjectMessage msg = getTestMessage(_session, _replyQueue, _messageSize, System.currentTimeMillis(), _persistent); + ObjectMessage msg = getTestMessage(_replyQueue, _messageSize, _persistent); msg.setLongProperty("timestamp", System.currentTimeMillis()); // Send the message and wait for a reply. - pingAndWaitForReply(msg, TIMEOUT); + pingAndWaitForReply(msg, BATCH_SIZE, TIMEOUT); // Introduce a short pause if desired. pause(SLEEP_TIME); @@ -299,4 +406,37 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _logger.debug("There was an interruption: " + e.getMessage(), e); } } + + public Queue getReplyQueue() + { + return _replyQueue; + } + + /** + * A connection listener that logs out any failover complete events. Could do more interesting things with this + * at some point... + */ + public static class FailoverNotifier implements ConnectionListener + { + public void bytesSent(long count) + { } + + public void bytesReceived(long count) + { } + + public boolean preFailover(boolean redirect) + { + return true; + } + + public boolean preResubscribe() + { + return true; + } + + public void failoverComplete() + { + _logger.info("App got failover complete callback."); + } + } } -- cgit v1.2.1 From 8e34903c0ea7167f03a97eae61c5e41dd0434eee Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 18 Jan 2007 16:58:35 +0000 Subject: (Pacth by Rupert Smith) Fixed mistake in PingPongProducer, it was creating its message counter after sending messages, so sometimes the onMessage loop had already received mesages before the counter was created. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@497498 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/requestreply/PingPongBouncer.java | 10 +++------- .../java/org/apache/qpid/requestreply/PingPongProducer.java | 12 ++++++------ 2 files changed, 9 insertions(+), 13 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java index d2a376fff0..e7fe180d43 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -125,16 +125,12 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen // Create a session to listen for messages on and one to send replies on, transactional depending on the // command line option. - Session consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); - Session producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); // Create the queue to listen for message on. Queue q = new AMQQueue(queueName); - MessageConsumer consumer = consumerSession.createConsumer(q, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); - - // Hang on to the sessions for the messages and replies. - _consumerSession = consumerSession; - _producerSession = producerSession; + MessageConsumer consumer = _consumerSession.createConsumer(q, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); _verbose = verbose; _persistent = persistent; diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 6956187b66..de8fbf9c39 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -215,7 +215,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } /** - * Primes the test loop by sending a few messages, then introducing a short wait. This allows the bounce back client + * Primes the test loop by sending a few messages, then introduces a short wait. This allows the bounce back client * on the other end a chance to configure its reply producer on the reply to destination. It is also worth calling * this a few times, in order to prime the JVMs JIT compilation. * @@ -309,6 +309,11 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, String messageCorrelationId = Long.toString(idGenerator.incrementAndGet()); message.setJMSCorrelationID(messageCorrelationId); + // Create a count down latch to count the number of replies with. This is created before the message is sent + // so that the message is not received before the count down is created. + CountDownLatch trafficLight = new CountDownLatch(numPings); + trafficLights.put(messageCorrelationId, trafficLight); + for (int i = 0; i < numPings; i++) { // Re-timestamp the message. @@ -323,17 +328,12 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Keep the messageId to correlate with the reply. //String messageId = message.getJMSMessageID(); - if (_verbose) { _logger.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); } // Block the current thread until a reply to the message is received, or it times out. - CountDownLatch trafficLight = new CountDownLatch(numPings); - trafficLights.put(messageCorrelationId, trafficLight); - - // Note that this call expects a timeout in nanoseconds, millisecond timeout is multiplied up. trafficLight.await(timeout, TimeUnit.MILLISECONDS); // Work out how many replies were receieved. -- cgit v1.2.1 From fc0633f1358f6036e1663d8839e01aef4b347c68 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Fri, 19 Jan 2007 10:28:50 +0000 Subject: refactored the constructor to allow subclasses use the super constructor git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@497766 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongProducer.java | 67 ++++++++++++++++------ 1 file changed, 50 insertions(+), 17 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index de8fbf9c39..00b01f1025 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -70,25 +70,25 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, private static final Logger _logger = Logger.getLogger(PingPongProducer.class); /** Used to set up a default message size. */ - private static final int DEFAULT_MESSAGE_SIZE = 0; + protected static final int DEFAULT_MESSAGE_SIZE = 0; /** Used to define how long to wait between pings. */ - private static final long SLEEP_TIME = 250; + protected static final long SLEEP_TIME = 250; /** Used to define how long to wait before assuming that a ping has timed out. */ - private static final long TIMEOUT = 3000; + protected static final long TIMEOUT = 9000; /** Holds the name of the queue to send pings on. */ private static final String PING_QUEUE_NAME = "ping"; /** The batch size. */ - private static final int BATCH_SIZE = 100; + protected static final int BATCH_SIZE = 100; /** Keeps track of the ping producer instance used in the run loop. */ private static PingPongProducer _pingProducer; - private static final int PREFETCH = 100; - private static final boolean NO_LOCAL = true; - private static final boolean EXCLUSIVE = false; + protected static final int PREFETCH = 100; + protected static final boolean NO_LOCAL = true; + protected static final boolean EXCLUSIVE = false; /** The number of priming loops to run. */ private static final int PRIMING_LOOPS = 3; @@ -102,6 +102,9 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, /** Holds the queue to send the ping replies to. */ private Queue _replyQueue; + /** Hold the known Queue where the producer will be sending message to*/ + private Queue _pingQueue; + /** Determines whether this producer sends persistent messages from the run method. */ private boolean _persistent; @@ -144,26 +147,56 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, setProducerSession((Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE)); _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + // Create producer and the consumer + createProducer(queueName, persistent); + createConsumer(selector); + + // Run a few priming pings to remove warm up time from test results. + prime(PRIMING_LOOPS); + + _persistent = persistent; + _messageSize = messageSize; + _verbose = verbose; + } + + /** + * Creates the queue and producer to send the pings on + * @param queueName + * @param persistent + * @throws JMSException + */ + public void createProducer(String queueName, boolean persistent) throws JMSException + { // Create a queue and producer to send the pings on. - Queue pingQueue = new AMQQueue(queueName); - _producer = (MessageProducer) getProducerSession().createProducer(pingQueue); + _pingQueue = new AMQQueue(queueName); + _producer = (MessageProducer) getProducerSession().createProducer(_pingQueue); _producer.setDisableMessageTimestamp(true); _producer.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + } + /** + * Creates the temporary queue to listen to the responses + * @param selector + * @throws JMSException + */ + public void createConsumer(String selector) throws JMSException + { // Create a temporary queue to get the pongs on. _replyQueue = _consumerSession.createTemporaryQueue(); // Create a message consumer to get the replies with and register this to be called back by it. MessageConsumer consumer = _consumerSession.createConsumer(_replyQueue, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); consumer.setMessageListener(this); + } - // Run a few priming pings to remove warm up time from test results. - prime(PRIMING_LOOPS); - - _persistent = persistent; - _messageSize = messageSize; + protected Session getConsumerSession() + { + return _consumerSession; + } - _verbose = verbose; + public Queue getPingQueue() + { + return _pingQueue; } /** @@ -185,8 +218,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Extract the command line. if (args.length < 2) { - System.err.println( - "Usage: TestPingPublisher [transacted] [persistent] [message size in bytes]"); + System.err.println("Usage: TestPingPublisher [verbose (true/false)] " + + "[transacted (true/false)] [persistent (true/false)] [message size in bytes]"); System.exit(0); } -- cgit v1.2.1 From 31b79a1343b533a7d20104058247760b1ae6f257 Mon Sep 17 00:00:00 2001 From: Marnie McCormack Date: Fri, 19 Jan 2007 11:54:26 +0000 Subject: Upgraded logging for JMSException to error as we always want to know afaik git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@497781 13f79535-47bb-0310-9956-ffa450edef68 --- .../perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java index db89b0d38a..43a010d8ef 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java @@ -153,7 +153,7 @@ class TestPingClient extends AbstractPingClient implements MessageListener } catch (JMSException e) { - _logger.debug("There was a JMSException: " + e.getMessage(), e); + _logger.error("There was a JMSException: " + e.getMessage(), e); } } } -- cgit v1.2.1 From f385fb5c752a554de01b949f78e4c0eb5a3ae802 Mon Sep 17 00:00:00 2001 From: Marnie McCormack Date: Fri, 19 Jan 2007 12:04:42 +0000 Subject: JMSException logged as error git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@497784 13f79535-47bb-0310-9956-ffa450edef68 --- .../perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java index 182a6228b1..37f6f7518e 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java @@ -184,7 +184,7 @@ class TestPingProducer extends AbstractPingProducer catch (JMSException e) { _publish = false; - _logger.debug("There was a JMSException: " + e.getMessage(), e); + _logger.error("There was a JMSException: " + e.getMessage(), e); } } } -- cgit v1.2.1 From 3cbedcd0e787093a4fe04ea5cd3105dda029228e Mon Sep 17 00:00:00 2001 From: Marnie McCormack Date: Fri, 19 Jan 2007 12:07:28 +0000 Subject: JMSException logged as error git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@497786 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/ping/TestPingSubscriber.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java index 001f1e3568..b43319744a 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java @@ -68,7 +68,7 @@ public class TestPingSubscriber } catch (JMSException jmse) { - // ignore + _logger.error("JMSException caught:" + jmse.getMessage(), jmse); } -- cgit v1.2.1 From 56c9945fab16ae5c2df607b4705a79ba85128674 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Fri, 19 Jan 2007 17:02:11 +0000 Subject: Added class to ping itself and a junit test for it. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@497878 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/ping/TestPingItself.java | 116 +++++++++++++++++++++ .../apache/qpid/requestreply/PingPongProducer.java | 32 ++++-- 2 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java new file mode 100644 index 0000000000..6bb4c08e6d --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java @@ -0,0 +1,116 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed 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.qpid.ping; + +import org.apache.qpid.requestreply.PingPongProducer; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.jms.Session; +import org.apache.qpid.jms.MessageProducer; +import org.apache.log4j.Logger; + +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.ObjectMessage; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Queue; +import java.net.InetAddress; + +/** + * This class is used to test sending and receiving messages to (pingQueue) and from a queue (replyQueue). + * The producer and consumer created by this test send and receive messages to and from the same Queue. ie. + * pingQueue and replyQueue are same. + * This class extends @see org.apache.qpid.requestreply.PingPongProducer which different ping and reply Queues + */ +public class TestPingItself extends PingPongProducer +{ + private static final Logger _logger = Logger.getLogger(TestPingItself.class); + + public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String queueName, + String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose) + throws Exception + { + super(brokerDetails, username, password, virtualpath, queueName, selector, transacted, persistent, messageSize, verbose); + } + + @Override + public void createConsumer(String selector) throws JMSException + { + // Create a message consumer to get the replies with and register this to be called back by it. + setReplyQueue(getPingQueue()); + MessageConsumer consumer = getConsumerSession().createConsumer(getReplyQueue(), PREFETCH, false, EXCLUSIVE, selector); + consumer.setMessageListener(this); + } + + + + /** + * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs + * to be started to bounce the pings back again. + * + *

    The command line takes from 2 to 4 arguments: + *

    + *
    brokerDetails The broker connection string. + *
    virtualPath The virtual path. + *
    transacted A boolean flag, telling this client whether or not to use transactions. + *
    size The size of ping messages to use, in bytes. + *
    + * + * @param args The command line arguments as defined above. + */ + public static void main(String[] args) throws Exception + { + // Extract the command line. + if (args.length < 2) + { + System.err.println("Usage: TestPingPublisher [verbose (true/false)] " + + "[transacted (true/false)] [persistent (true/false)] [message size in bytes]"); + System.exit(0); + } + + String brokerDetails = args[0]; + String virtualpath = args[1]; + boolean verbose = (args.length >= 3) ? Boolean.parseBoolean(args[2]) : true; + boolean transacted = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; + boolean persistent = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; + int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; + + String queue = "ping_"+ System.currentTimeMillis(); + _logger.info("Queue:" + queue + ", Transacted:" + transacted + ", persistent:"+ persistent + + ",MessageSize:" + messageSize + " bytes"); + + // Create a ping producer to handle the request/wait/reply cycle. + TestPingItself pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, + transacted, persistent, messageSize, verbose); + pingItself.getConnection().start(); + + // Run a few priming pings to remove warm up time from test results. + pingItself.prime(PRIMING_LOOPS); + // Create a shutdown hook to terminate the ping-pong producer. + Runtime.getRuntime().addShutdownHook(pingItself.getShutdownHook()); + + // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. + pingItself.getConnection().setExceptionListener(pingItself); + + // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. + Thread pingThread = new Thread(pingItself); + pingThread.run(); + pingThread.join(); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 00b01f1025..031a5c5299 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -79,7 +79,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, protected static final long TIMEOUT = 9000; /** Holds the name of the queue to send pings on. */ - private static final String PING_QUEUE_NAME = "ping"; + protected static final String PING_QUEUE_NAME = "ping"; /** The batch size. */ protected static final int BATCH_SIZE = 100; @@ -91,7 +91,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, protected static final boolean EXCLUSIVE = false; /** The number of priming loops to run. */ - private static final int PRIMING_LOOPS = 3; + protected static final int PRIMING_LOOPS = 3; /** A source for providing sequential unique correlation ids. */ private AtomicLong idGenerator = new AtomicLong(0L); @@ -106,19 +106,19 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, private Queue _pingQueue; /** Determines whether this producer sends persistent messages from the run method. */ - private boolean _persistent; + protected boolean _persistent; /** Holds the message size to send, from the run method. */ - private int _messageSize; + protected int _messageSize; /** Holds a map from message ids to latches on which threads wait for replies. */ private Map trafficLights = new HashMap(); /** Used to indicate that the ping loop should print out whenever it pings. */ - private boolean _verbose = false; - - private Session _consumerSession; + protected boolean _verbose = false; + protected Session _consumerSession; + /** * Creates a ping pong producer with the specified connection details and type. * @@ -151,9 +151,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, createProducer(queueName, persistent); createConsumer(selector); - // Run a few priming pings to remove warm up time from test results. - prime(PRIMING_LOOPS); - _persistent = persistent; _messageSize = messageSize; _verbose = verbose; @@ -168,7 +165,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, public void createProducer(String queueName, boolean persistent) throws JMSException { // Create a queue and producer to send the pings on. - _pingQueue = new AMQQueue(queueName); + if (_pingQueue == null) + _pingQueue = new AMQQueue(queueName); _producer = (MessageProducer) getProducerSession().createProducer(_pingQueue); _producer.setDisableMessageTimestamp(true); _producer.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); @@ -199,6 +197,11 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, return _pingQueue; } + protected void setPingQueue(Queue queue) + { + _pingQueue = queue; + } + /** * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs * to be started to bounce the pings back again. @@ -235,6 +238,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, persistent, messageSize, verbose); _pingProducer.getConnection().start(); + // Run a few priming pings to remove warm up time from test results. + _pingProducer.prime(PRIMING_LOOPS); // Create a shutdown hook to terminate the ping-pong producer. Runtime.getRuntime().addShutdownHook(_pingProducer.getShutdownHook()); @@ -445,6 +450,11 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, return _replyQueue; } + protected void setReplyQueue(Queue queue) + { + _replyQueue = queue; + } + /** * A connection listener that logs out any failover complete events. Could do more interesting things with this * at some point... -- cgit v1.2.1 From ec5bff29cb62c537eebca943d5647de3b994dd40 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Mon, 22 Jan 2007 16:41:23 +0000 Subject: performance Ping tests modified for scalability test. Now tests with multiple queues can be performed. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@498687 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/AbstractPingProducer.java | 42 ++++++++ .../java/org/apache/qpid/ping/TestPingItself.java | 25 ++++- .../apache/qpid/requestreply/PingPongProducer.java | 118 ++++++++++++++++----- 3 files changed, 154 insertions(+), 31 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java index bedd6e3d16..513e1609aa 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java @@ -1,14 +1,19 @@ package org.apache.qpid.ping; import java.text.SimpleDateFormat; +import java.util.List; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; import javax.jms.*; import org.apache.log4j.Logger; import org.apache.qpid.client.AMQNoConsumersException; +import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.jms.Session; +import org.apache.qpid.framing.AMQShortString; /** * This abstract class captures functionality that is common to all ping producers. It provides functionality to @@ -41,6 +46,12 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene /** Holds the producer session, need to create test messages. */ private Session _producerSession; + + /** holds the no of queues the tests will be using to send messages. By default it will be 1 */ + private int _queueCount; + private static AtomicInteger _queueSequenceID = new AtomicInteger(); + private List _queues = new ArrayList(); + /** * Convenience method for a short pause. * @@ -169,6 +180,37 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene this._producerSession = session; } + public int getQueueCount() + { + return _queueCount; + } + + public void setQueueCount(int queueCount) + { + this._queueCount = queueCount; + } + + /** + * Creates queues dynamically and adds to the queues list. This is when the test is being done with + * multiple queues. + * @param queueCount + */ + protected void createQueues(int queueCount) + { + for (int i = 0; i < queueCount; i++) + { + AMQShortString name = new AMQShortString("Queue_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); + AMQQueue queue = new AMQQueue(name, name, false, false, false); + + _queues.add(queue); + } + } + + protected Queue getQueue(int index) + { + return _queues.get(index); + } + /** * Convenience method to commit the transaction on the session associated with this pinger. * diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java index 6bb4c08e6d..3c6c42d92b 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java @@ -31,6 +31,8 @@ import javax.jms.Connection; import javax.jms.DeliveryMode; import javax.jms.Queue; import java.net.InetAddress; +import java.util.List; +import java.util.ArrayList; /** * This class is used to test sending and receiving messages to (pingQueue) and from a queue (replyQueue). @@ -41,7 +43,7 @@ import java.net.InetAddress; public class TestPingItself extends PingPongProducer { private static final Logger _logger = Logger.getLogger(TestPingItself.class); - + public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String queueName, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose) throws Exception @@ -49,7 +51,26 @@ public class TestPingItself extends PingPongProducer super(brokerDetails, username, password, virtualpath, queueName, selector, transacted, persistent, messageSize, verbose); } + public TestPingItself(String brokerDetails, String username, String password, String virtualpath, int queueCount, + String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose) + throws Exception + { + super(brokerDetails, username, password, virtualpath, transacted); + setQueueCount(queueCount); + createQueues(queueCount); + + _persistent = persistent; + _messageSize = messageSize; + _verbose = verbose; + + createConsumers(selector); + createProducer(); + } + @Override + /** + * Sets the replyQueue to be the same as ping queue. + */ public void createConsumer(String selector) throws JMSException { // Create a message consumer to get the replies with and register this to be called back by it. @@ -58,8 +79,6 @@ public class TestPingItself extends PingPongProducer consumer.setMessageListener(this); } - - /** * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs * to be started to bounce the pings back again. diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 031a5c5299..0b5f040b90 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -118,7 +118,22 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, protected boolean _verbose = false; protected Session _consumerSession; - + + protected PingPongProducer(String brokerDetails, String username, String password, String virtualpath, + boolean transacted) + throws Exception + { + // Create a connection to the broker. + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); + + setConnection(new AMQConnection(brokerDetails, username, password, clientID, virtualpath)); + + // Create transactional or non-transactional sessions, based on the command line arguments. + setProducerSession((Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE)); + _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + } + /** * Creates a ping pong producer with the specified connection details and type. * @@ -137,39 +152,39 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose) throws Exception { - // Create a connection to the broker. - InetAddress address = InetAddress.getLocalHost(); - String clientID = address.getHostName() + System.currentTimeMillis(); - - setConnection(new AMQConnection(brokerDetails, username, password, clientID, virtualpath)); - - // Create transactional or non-transactional sessions, based on the command line arguments. - setProducerSession((Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE)); - _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); - - // Create producer and the consumer - createProducer(queueName, persistent); - createConsumer(selector); + this(brokerDetails, username, password, virtualpath, transacted); + _pingQueue = new AMQQueue(queueName); _persistent = persistent; _messageSize = messageSize; _verbose = verbose; + + // Create producer and the consumer + createProducer(); + createConsumer(selector); } /** - * Creates the queue and producer to send the pings on - * @param queueName - * @param persistent + * Creates the producer to send the pings on. If the tests are with nultiple queues, then producer + * is created with null destination, so that any destination can be specified while sending * @throws JMSException */ - public void createProducer(String queueName, boolean persistent) throws JMSException + public void createProducer() throws JMSException { - // Create a queue and producer to send the pings on. - if (_pingQueue == null) - _pingQueue = new AMQQueue(queueName); - _producer = (MessageProducer) getProducerSession().createProducer(_pingQueue); + if (getQueueCount() > 1) + { + // create producer with initial destination as null for test with multiple queues + // In this case, a different destination will be used while sending the message + _producer = (MessageProducer) getProducerSession().createProducer(null); + } + else + { + // Create a queue and producer to send the pings on. + _producer = (MessageProducer) getProducerSession().createProducer(_pingQueue); + + } _producer.setDisableMessageTimestamp(true); - _producer.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); } /** @@ -187,6 +202,20 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, consumer.setMessageListener(this); } + /** + * Creates consumer instances for each queue. This is used when test is being done with multiple queues. + * @param selector + * @throws JMSException + */ + public void createConsumers(String selector) throws JMSException + { + for (int i = 0; i < getQueueCount(); i++) + { + MessageConsumer consumer = getConsumerSession().createConsumer(getQueue(i), PREFETCH, false, EXCLUSIVE, selector); + consumer.setMessageListener(this); + } + } + protected Session getConsumerSession() { return _consumerSession; @@ -296,6 +325,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, if (_verbose) { _logger.info(timestampFormatter.format(new Date()) + ": Got reply with correlation id, " + correlationID); + //_logger.debug("Received from : " + message.getJMSDestination()); } // Turn the traffic light to green. @@ -352,12 +382,20 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, CountDownLatch trafficLight = new CountDownLatch(numPings); trafficLights.put(messageCorrelationId, trafficLight); - for (int i = 0; i < numPings; i++) + if (getQueueCount() > 1) { - // Re-timestamp the message. - message.setLongProperty("timestamp", System.currentTimeMillis()); - - _producer.send(message); + // If test is with multiple queues + pingMultipleQueues(message, numPings); + } + else + { + // If test is with one Queue only + for (int i = 0; i < numPings; i++) + { + // Re-timestamp the message. + message.setLongProperty("timestamp", System.currentTimeMillis()); + _producer.send(message); + } } // Commit the transaction if running in transactional mode. This must happen now, rather than at the end of @@ -389,6 +427,30 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, return numReplies; } + /** + * When the test is being performed with multiple queues, then this method will be used, which has a loop to + * pick up the next queue from the queues list and sends message to it. + * @param message + * @param numPings + * @throws JMSException + */ + private void pingMultipleQueues(Message message, int numPings) throws JMSException + { + int queueIndex = 0; + for (int i = 0; i < numPings; i++) + { + // Re-timestamp the message. + message.setLongProperty("timestamp", System.currentTimeMillis()); + _producer.send(getQueue(queueIndex++), message); + + // reset the counter to get the first queue + if (queueIndex == getQueueCount() -1) + { + queueIndex = 0; + } + } + } + /** * Sends the specified ping message but does not wait for a correlating reply. * -- cgit v1.2.1 From 601fa8a026e7488bbb67e3f809f8255e2e6aeedd Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 22 Jan 2007 17:30:29 +0000 Subject: (Patch submitted by Rupert Smith) Added configurations for all performance test setups to the pom. Commented out to not break build. Waiting on junit-toolkit-maven-plugin being added to maven repository. Create a throttle utility class and tests for it. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@498720 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/AbstractPingProducer.java | 3 +- .../main/java/org/apache/qpid/ping/Throttle.java | 66 ++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java index 513e1609aa..1877a23056 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java @@ -1,5 +1,6 @@ package org.apache.qpid.ping; +import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.List; import java.util.ArrayList; @@ -35,7 +36,7 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene private static final Logger _logger = Logger.getLogger(AbstractPingProducer.class); /** Used to format time stamping output. */ - protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); + protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); /** Used to tell the ping loop when to terminate, it only runs while this is true. */ protected boolean _publish = true; diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java new file mode 100644 index 0000000000..9fb637149b --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java @@ -0,0 +1,66 @@ +package org.apache.qpid.ping; + +/** + * Throttle is a helper class used in situations where a controlled rate of processing is desired. It allows a certain + * number of operations-per-second to be defined and supplies a {@link #throttle} method that can only be called at + * most at that rate. The first call to the throttle method will return immediately, subsequent calls will introduce + * a short pause to fill out the remainder of the current cycle to attain the desired rate. If there is no remainder + * left then it will return immediately. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    + * + * @author Rupert Smith + */ +public class Throttle +{ + /** Holds the length of the cycle in nano seconds. */ + long cycleLengthNanos = 0L; + + /** Records the nano time of the last call to the throttle method. */ + long lastTimeNanos = 0L; + + /** + * Sets up the desired rate of operation per second that the throttle method should restrict to. + * + * @param opsPerSecond The maximum number of calls per second that the throttle method will take. + */ + public void setRate(int opsPerSecond) + { + // Calculate the length of a cycle. + cycleLengthNanos = 1000000000 / opsPerSecond; + } + + /** + * Introduces a short pause to fill out any time left in the cycle since this method was last called, of length + * defined by a call to the {@link #setRate} method. + */ + public void throttle() + { + // Record the time now. + long currentTimeNanos = System.nanoTime(); + + // Check if there is any time remaining in the current cycle and introduce a short wait to fill out the + // remainder of the cycle if needed. + long remainingTimeNanos = cycleLengthNanos - (currentTimeNanos - lastTimeNanos); + + if (remainingTimeNanos > 0) + { + long milliWait = remainingTimeNanos / 1000000; + int nanoWait = (int) (remainingTimeNanos % 1000000); + + try + { + Thread.currentThread().sleep(milliWait, nanoWait); + } + catch (InterruptedException e) + { + // Just ignore this? + } + } + + // Keep the time of the last call to this method to calculate the next cycle. + lastTimeNanos = currentTimeNanos; + } +} -- cgit v1.2.1 From 12c8ec5bc9c89993e87e11b626e9d9f88bdd5cdc Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 23 Jan 2007 09:39:56 +0000 Subject: Added ability to cause failover before/after commit/sends Added batch size ability. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@498965 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/AbstractPingClient.java | 47 ++++- .../org/apache/qpid/ping/AbstractPingProducer.java | 183 ++++++++++++++---- .../java/org/apache/qpid/ping/TestPingClient.java | 53 +++++- .../java/org/apache/qpid/ping/TestPingItself.java | 64 +++++-- .../org/apache/qpid/ping/TestPingProducer.java | 93 +++++++-- .../apache/qpid/requestreply/PingPongProducer.java | 208 +++++++++++++++------ 6 files changed, 508 insertions(+), 140 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java index 7c82710a3f..c04a8a7d96 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java @@ -1,6 +1,7 @@ package org.apache.qpid.ping; import java.text.SimpleDateFormat; +import java.io.IOException; import javax.jms.Connection; import javax.jms.JMSException; @@ -13,7 +14,7 @@ import org.apache.qpid.jms.Session; /** * Provides functionality common to all ping clients. Provides the ability to manage a session and a convenience method * to commit on the current transaction. - * + *

    *

    *
    CRC Card
    Responsibilities Collaborations *
    Commit the current transcation. @@ -29,6 +30,9 @@ public abstract class AbstractPingClient private static final Logger _logger = Logger.getLogger(TestPingClient.class); private AMQConnection _connection; + protected boolean _failBeforeCommit = false; + protected boolean _failAfterCommit = false; + public AMQConnection getConnection() { return _connection; @@ -50,7 +54,20 @@ public abstract class AbstractPingClient { try { + if (_failBeforeCommit) + { + _logger.trace("Failing Before Commit"); + doFailover(); + } + session.commit(); + + if (_failAfterCommit) + { + _logger.trace("Failing After Commit"); + doFailover(); + } + _logger.trace("Session Commited."); } catch (JMSException e) @@ -72,4 +89,32 @@ public abstract class AbstractPingClient } } } + + protected void doFailover(String broker) + { + System.out.println("Kill Broker " + broker + " now."); + try + { + System.in.read(); + } + catch (IOException e) + { + } + System.out.println("Continuing."); + } + + protected void doFailover() + { + System.out.println("Kill Broker now."); + try + { + System.in.read(); + } + catch (IOException e) + { + } + System.out.println("Continuing."); + + } + } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java index 1877a23056..4cca77a70e 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java @@ -2,17 +2,23 @@ package org.apache.qpid.ping; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.io.IOException; import java.util.List; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; import javax.jms.*; +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageProducer; import org.apache.log4j.Logger; import org.apache.qpid.client.AMQNoConsumersException; +import org.apache.qpid.client.BasicMessageProducer; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.jms.*; import org.apache.qpid.jms.Session; import org.apache.qpid.framing.AMQShortString; @@ -20,7 +26,7 @@ import org.apache.qpid.framing.AMQShortString; * This abstract class captures functionality that is common to all ping producers. It provides functionality to * manage a session, and a convenience method to commit a transaction on the session. It also provides a framework * for running a ping loop, and terminating that loop on exceptions or a shutdown handler. - * + *

    *

    *
    CRC Card
    Responsibilities Collaborations *
    Manage the connection. @@ -35,24 +41,48 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene { private static final Logger _logger = Logger.getLogger(AbstractPingProducer.class); - /** Used to format time stamping output. */ + /** + * Used to format time stamping output. + */ protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); - /** Used to tell the ping loop when to terminate, it only runs while this is true. */ + /** + * Used to tell the ping loop when to terminate, it only runs while this is true. + */ protected boolean _publish = true; - /** Holds the connection handle to the broker. */ + /** + * Holds the connection handle to the broker. + */ private Connection _connection; - /** Holds the producer session, need to create test messages. */ + /** + * Holds the producer session, need to create test messages. + */ private Session _producerSession; - /** holds the no of queues the tests will be using to send messages. By default it will be 1 */ - private int _queueCount; + /** + * holds the no of queues the tests will be using to send messages. By default it will be 1 + */ + protected int _queueCount; private static AtomicInteger _queueSequenceID = new AtomicInteger(); private List _queues = new ArrayList(); + /** + * Holds the message producer to send the pings through. + */ + protected org.apache.qpid.jms.MessageProducer _producer; + + protected boolean _failBeforeCommit = false; + protected boolean _failAfterCommit = false; + protected boolean _failBeforeSend = false; + protected boolean _failAfterSend = false; + + protected int _sentMessages = 0; + protected int _batchSize = 1; + + /** * Convenience method for a short pause. * @@ -67,7 +97,8 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene Thread.sleep(sleepTime); } catch (InterruptedException ie) - { } + { + } } } @@ -78,9 +109,7 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene * * @param replyQueue The reply-to destination for the message. * @param messageSize The desired size of the message in bytes. - * * @return A freshly generated test message. - * * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. */ public ObjectMessage getTestMessage(Queue replyQueue, int messageSize, boolean persistent) throws JMSException @@ -153,12 +182,12 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene public Thread getShutdownHook() { return new Thread(new Runnable() + { + public void run() { - public void run() - { - stop(); - } - }); + stop(); + } + }); } public Connection getConnection() @@ -181,6 +210,12 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene this._producerSession = session; } + + protected void commitTx() throws JMSException + { + commitTx(getProducerSession()); + } + public int getQueueCount() { return _queueCount; @@ -194,6 +229,7 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene /** * Creates queues dynamically and adds to the queues list. This is when the test is being done with * multiple queues. + * * @param queueCount */ protected void createQueues(int queueCount) @@ -202,7 +238,7 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene { AMQShortString name = new AMQShortString("Queue_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); AMQQueue queue = new AMQQueue(name, name, false, false, false); - + _queues.add(queue); } } @@ -219,36 +255,107 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene */ protected void commitTx(Session session) throws JMSException { - if (session.getTransacted()) + if ((++_sentMessages % _batchSize) == 0) { - try + if (session.getTransacted()) { - session.commit(); - _logger.trace("Session Commited."); - } - catch (JMSException e) - { - _logger.trace("JMSException on commit:" + e.getMessage(), e); - - // Warn that the bounce back client is not available. - if (e.getLinkedException() instanceof AMQNoConsumersException) - { - _logger.debug("No consumers on queue."); - } - try { - session.rollback(); - _logger.trace("Message rolled back."); + if (_failBeforeCommit) + { + _logger.trace("Failing Before Commit"); + doFailover(); + } + + session.commit(); + + if (_failAfterCommit) + { + _logger.trace("Failing After Commit"); + doFailover(); + } + _logger.trace("Session Commited."); } - catch (JMSException jmse) + catch (JMSException e) { - _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); - - // Both commit and rollback failed. Throw the rollback exception. - throw jmse; + _logger.trace("JMSException on commit:" + e.getMessage(), e); + + // Warn that the bounce back client is not available. + if (e.getLinkedException() instanceof AMQNoConsumersException) + { + _logger.debug("No consumers on queue."); + } + + try + { + session.rollback(); + _logger.trace("Message rolled back."); + } + catch (JMSException jmse) + { + _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); + + // Both commit and rollback failed. Throw the rollback exception. + throw jmse; + } } } } } + + protected void sendMessage(Message message) throws JMSException + { + sendMessage(null, message); + } + + protected void sendMessage(Queue q, Message message) throws JMSException + { + if (_failBeforeSend) + { + _logger.trace("Failing Before Send"); + doFailover(); + } + + if (q == null) + { + _producer.send(message); + } + else + { + _producer.send(q, message); + } + + if (_failAfterSend) + { + _logger.trace("Failing After Send"); + doFailover(); + } + } + + protected void doFailover(String broker) + { + System.out.println("Kill Broker " + broker + " now then press return"); + try + { + System.in.read(); + } + catch (IOException e) + { + } + System.out.println("Continuing."); + } + + protected void doFailover() + { + System.out.println("Kill Broker now then press return"); + try + { + System.in.read(); + } + catch (IOException e) + { + } + System.out.println("Continuing."); + + } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java index 43a010d8ef..949ace20e1 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java @@ -34,11 +34,11 @@ import org.apache.qpid.jms.Session; * PingClient is a message listener that received time stamped ping messages. It can work out how long a ping took, * provided that its clokc is synchronized to that of the ping producer, or by running it on the same machine (or jvm) * as the ping producer. - * + *

    *

    There is a verbose mode flag which causes information about each ping to be output to the console * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should * be disabled for real timing tests as writing to the console will slow things down. - * + *

    *

    *
    CRC Card
    Responsibilities Collaborations *
    Provide command line invocation to start the ping consumer on a configurable broker url. @@ -50,10 +50,14 @@ class TestPingClient extends AbstractPingClient implements MessageListener { private static final Logger _logger = Logger.getLogger(TestPingClient.class); - /** Used to indicate that the reply generator should log timing info to the console (logger info level). */ + /** + * Used to indicate that the reply generator should log timing info to the console (logger info level). + */ private boolean _verbose = false; - /** The producer session. */ + /** + * The producer session. + */ private Session _consumerSession; /** @@ -67,11 +71,11 @@ class TestPingClient extends AbstractPingClient implements MessageListener * @param transacted * @param selector * @param verbose - * - * @throws Exception All underlying exceptions allowed to fall through. This is only test code... + * @param afterCommit + *@param beforeCommit @throws Exception All underlying exceptions allowed to fall through. This is only test code... */ public TestPingClient(String brokerDetails, String username, String password, String queueName, String virtualpath, - boolean transacted, String selector, boolean verbose) throws Exception + boolean transacted, String selector, boolean verbose, boolean afterCommit, boolean beforeCommit) throws Exception { // Create a connection to the broker. InetAddress address = InetAddress.getLocalHost(); @@ -85,10 +89,15 @@ class TestPingClient extends AbstractPingClient implements MessageListener // Connect a consumer to the ping queue and register this to be called back by it. Queue q = new AMQQueue(queueName); MessageConsumer consumer = _consumerSession.createConsumer(q, 1, false, false, selector); + consumer.setMessageListener(this); // Hang on to the verbose flag setting. _verbose = verbose; + + // Set failover interrupts + _failAfterCommit = afterCommit; + _failBeforeCommit = beforeCommit; } /** @@ -104,7 +113,7 @@ class TestPingClient extends AbstractPingClient implements MessageListener if (args.length < 4) { System.out.println( - "Usage: brokerdetails username password virtual-path [queueName] [verbose] [transacted] [selector]"); + "Usage: brokerdetails username password virtual-path [queueName] [verbose] [transacted] [selector] [failover::commit]"); System.exit(1); } @@ -118,14 +127,38 @@ class TestPingClient extends AbstractPingClient implements MessageListener boolean transacted = (args.length >= 7) ? Boolean.parseBoolean(args[6]) : false; String selector = (args.length == 8) ? args[7] : null; + boolean afterCommit = false; + boolean beforeCommit = false; + + for (String arg : args) + { + if (arg.startsWith("failover:")) + { + //failover:: + String[] parts = arg.split(":"); + if (parts.length == 3) + { + if (parts[2].equals("commit")) + { + afterCommit = parts[1].equals("after"); + beforeCommit = parts[1].equals("before"); + } + } + else + { + System.out.println("Unrecognized failover request:" + arg); + } + } + } + // Create the test ping client and set it running. TestPingClient pingClient = - new TestPingClient(brokerDetails, username, password, queueName, virtualpath, transacted, selector, verbose); + new TestPingClient(brokerDetails, username, password, queueName, virtualpath, transacted, selector, verbose, afterCommit, beforeCommit); + pingClient.getConnection().start(); System.out.println("Waiting..."); } - /** * This is a callback method that is notified of all messages for which this has been registered as a message * listener on a message consumer. diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java index 3c6c42d92b..579816870f 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java @@ -45,18 +45,24 @@ public class TestPingItself extends PingPongProducer private static final Logger _logger = Logger.getLogger(TestPingItself.class); public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String queueName, - String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose) + String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, + boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, + int batchSize) throws Exception { - super(brokerDetails, username, password, virtualpath, queueName, selector, transacted, persistent, messageSize, verbose); + super(brokerDetails, username, password, virtualpath, queueName, selector, transacted, persistent, messageSize, + verbose, afterCommit, beforeCommit, afterSend, beforeSend, batchSize, 0); } - public TestPingItself(String brokerDetails, String username, String password, String virtualpath, int queueCount, - String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose) + public TestPingItself(String brokerDetails, String username, String password, String virtualpath, + String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, + boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, + int batchSize, int queueCount) throws Exception { - super(brokerDetails, username, password, virtualpath, transacted); - setQueueCount(queueCount); + super(brokerDetails, username, password, virtualpath, null, null, transacted, persistent, messageSize, + verbose, afterCommit, beforeCommit, afterSend, beforeSend, batchSize, queueCount); + createQueues(queueCount); _persistent = persistent; @@ -82,7 +88,7 @@ public class TestPingItself extends PingPongProducer /** * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs * to be started to bounce the pings back again. - * + *

    *

    The command line takes from 2 to 4 arguments: *

    *
    brokerDetails The broker connection string. @@ -99,7 +105,7 @@ public class TestPingItself extends PingPongProducer if (args.length < 2) { System.err.println("Usage: TestPingPublisher [verbose (true/false)] " + - "[transacted (true/false)] [persistent (true/false)] [message size in bytes]"); + "[transacted (true/false)] [persistent (true/false)] [message size in bytes]"); System.exit(0); } @@ -109,14 +115,50 @@ public class TestPingItself extends PingPongProducer boolean transacted = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; boolean persistent = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; + int batchSize = (args.length >= 7) ? Integer.parseInt(args[6]) : 1; - String queue = "ping_"+ System.currentTimeMillis(); - _logger.info("Queue:" + queue + ", Transacted:" + transacted + ", persistent:"+ persistent + + String queue = "ping_" + System.currentTimeMillis(); + _logger.info("Queue:" + queue + ", Transacted:" + transacted + ", persistent:" + persistent + ",MessageSize:" + messageSize + " bytes"); + + boolean afterCommit = false; + boolean beforeCommit = false; + boolean afterSend = false; + boolean beforeSend = false; + + for (String arg : args) + { + if (arg.startsWith("failover:")) + { + //failover:: + String[] parts = arg.split(":"); + if (parts.length == 3) + { + if (parts[2].equals("commit")) + { + afterCommit = parts[1].equals("after"); + beforeCommit = parts[1].equals("before"); + } + + if (parts[2].equals("send")) + { + afterSend = parts[1].equals("after"); + beforeSend = parts[1].equals("before"); + } + } + else + { + System.out.println("Unrecognized failover request:" + arg); + } + } + } + // Create a ping producer to handle the request/wait/reply cycle. TestPingItself pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, - transacted, persistent, messageSize, verbose); + transacted, persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, + batchSize); pingItself.getConnection().start(); // Run a few priming pings to remove warm up time from test results. diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java index 37f6f7518e..e53d7bb521 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java @@ -37,12 +37,12 @@ import org.apache.qpid.jms.Session; * PingProducer is a client that sends timestamped pings to a queue. It is designed to be run from the command line * as a stand alone test tool, but it may also be fairly easily instantiated by other code by supplying a session and * configured message producer. - * + *

    *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop * does all its work through helper methods, so that code wishing to run a ping cycle is not forced to do so * by starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is * also registered to terminate the ping loop cleanly. - * + *

    *

    *
    CRC Card
    Responsibilities Collaborations *
    Provide a ping cycle. @@ -53,31 +53,42 @@ class TestPingProducer extends AbstractPingProducer { private static final Logger _logger = Logger.getLogger(TestPingProducer.class); - /** Used to set up a default message size. */ + /** + * Used to set up a default message size. + */ private static final int DEFAULT_MESSAGE_SIZE = 0; - /** Used to define how long to wait between pings. */ + /** + * Used to define how long to wait between pings. + */ private static final long SLEEP_TIME = 250; - /** Holds the name of the queue to send pings on. */ + /** + * Holds the name of the queue to send pings on. + */ private static final String PING_QUEUE_NAME = "ping"; private static TestPingProducer _pingProducer; - /** Holds the message producer to send the pings through. */ - private MessageProducer _producer; - - /** Determines whether this producer sends persistent messages from the run method. */ + /** + * Determines whether this producer sends persistent messages from the run method. + */ private boolean _persistent = false; - /** Holds the message size to send, from the run method. */ + /** + * Holds the message size to send, from the run method. + */ private int _messageSize = DEFAULT_MESSAGE_SIZE; - /** Used to indicate that the ping loop should print out whenever it pings. */ + /** + * Used to indicate that the ping loop should print out whenever it pings. + */ private boolean _verbose = false; + public TestPingProducer(String brokerDetails, String username, String password, String virtualpath, String queueName, - boolean transacted, boolean persistent, int messageSize, boolean verbose) throws Exception + boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, + boolean beforeCommit, boolean afterSend, boolean beforeSend,int batchSize) throws Exception { // Create a connection to the broker. InetAddress address = InetAddress.getLocalHost(); @@ -96,6 +107,14 @@ class TestPingProducer extends AbstractPingProducer _messageSize = messageSize; _verbose = verbose; + + // Set failover interrupts + _failAfterCommit = afterCommit; + _failBeforeCommit = beforeCommit; + _failAfterSend = afterSend; + _failBeforeSend = beforeSend; + _sentMessages = 0; + _batchSize = batchSize; } /** @@ -110,7 +129,8 @@ class TestPingProducer extends AbstractPingProducer if (args.length < 2) { System.err.println( - "Usage: TestPingPublisher [verbose] [transacted] [persistent] [message size in bytes]"); + "Usage: TestPingPublisher "+ + "[ "); System.exit(0); } @@ -120,10 +140,46 @@ class TestPingProducer extends AbstractPingProducer boolean transacted = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; boolean persistent = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; + int batchSize = (args.length >= 7) ? Integer.parseInt(args[6]) : 1; + + + boolean afterCommit = false; + boolean beforeCommit = false; + boolean afterSend = false; + boolean beforeSend = false; + + for (String arg : args) + { + if (arg.startsWith("failover:")) + { + //failover:: + String[] parts = arg.split(":"); + if (parts.length == 3) + { + if (parts[2].equals("commit")) + { + afterCommit = parts[1].equals("after"); + beforeCommit = parts[1].equals("before"); + } + + if (parts[2].equals("send")) + { + afterSend = parts[1].equals("after"); + beforeSend = parts[1].equals("before"); + } + } + else + { + System.out.println("Unrecognized failover request:" + arg); + } + } + } // Create a ping producer to generate the pings. - _pingProducer = new TestPingProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, transacted, - persistent, messageSize, verbose); + _pingProducer = new TestPingProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, + transacted, persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, + batchSize); // Start the connection running. _pingProducer.getConnection().start(); @@ -144,19 +200,18 @@ class TestPingProducer extends AbstractPingProducer * Sends the specified ping message. * * @param message The message to send. - * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ public void ping(Message message) throws JMSException { - _producer.send(message); + sendMessage(message); // Keep the messageId to correlate with the reply. String messageId = message.getJMSMessageID(); // Commit the transaction if running in transactional mode. This must happen now, rather than at the end of - // this method, as the message will not be sent until the transaction is committed. - commitTx(getProducerSession()); + // this method, as the message will not be sent until the transaction is committed. + commitTx(); } /** diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 0b5f040b90..3c3e31dd55 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -44,17 +44,17 @@ import org.apache.qpid.ping.AbstractPingProducer; * client (see {@link PingPongBouncer} for the bounce back client). It is designed to be run from the command line * as a stand alone test tool, but it may also be fairly easily instantiated by other code by supplying a session, * message producer and message consumer to run the ping-pong cycle on. - * + *

    *

    The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. * This means that this class has to do some work to correlate pings with pongs; it expectes the original message * id in the ping to be bounced back in the correlation id. If a new temporary queue per ping were used, then * this correlation would not need to be done. - * + *

    *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so * by starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is * also registered to terminate the ping-pong loop cleanly. - * + *

    *

    *
    CRC Card
    Responsibilities Collaborations *
    Provide a ping and wait for response cycle. @@ -62,65 +62,91 @@ import org.apache.qpid.ping.AbstractPingProducer; *
    * * @todo Make temp queue per ping a command line option. - * * @todo Make the queue name a command line option. */ public class PingPongProducer extends AbstractPingProducer implements Runnable, MessageListener, ExceptionListener { private static final Logger _logger = Logger.getLogger(PingPongProducer.class); - /** Used to set up a default message size. */ + /** + * Used to set up a default message size. + */ protected static final int DEFAULT_MESSAGE_SIZE = 0; - /** Used to define how long to wait between pings. */ + /** + * Used to define how long to wait between pings. + */ protected static final long SLEEP_TIME = 250; - /** Used to define how long to wait before assuming that a ping has timed out. */ + /** + * Used to define how long to wait before assuming that a ping has timed out. + */ protected static final long TIMEOUT = 9000; - /** Holds the name of the queue to send pings on. */ + /** + * Holds the name of the queue to send pings on. + */ protected static final String PING_QUEUE_NAME = "ping"; - /** The batch size. */ + /** + * The batch size. + */ protected static final int BATCH_SIZE = 100; - /** Keeps track of the ping producer instance used in the run loop. */ + /** + * Keeps track of the ping producer instance used in the run loop. + */ private static PingPongProducer _pingProducer; protected static final int PREFETCH = 100; protected static final boolean NO_LOCAL = true; protected static final boolean EXCLUSIVE = false; - /** The number of priming loops to run. */ + /** + * The number of priming loops to run. + */ protected static final int PRIMING_LOOPS = 3; - /** A source for providing sequential unique correlation ids. */ + /** + * A source for providing sequential unique correlation ids. + */ private AtomicLong idGenerator = new AtomicLong(0L); - /** Holds the message producer to send the pings through. */ - private MessageProducer _producer; - - /** Holds the queue to send the ping replies to. */ + /** + * Holds the queue to send the ping replies to. + */ private Queue _replyQueue; - /** Hold the known Queue where the producer will be sending message to*/ + /** + * Hold the known Queue where the producer will be sending message to + */ private Queue _pingQueue; - /** Determines whether this producer sends persistent messages from the run method. */ + /** + * Determines whether this producer sends persistent messages from the run method. + */ protected boolean _persistent; - /** Holds the message size to send, from the run method. */ + /** + * Holds the message size to send, from the run method. + */ protected int _messageSize; - /** Holds a map from message ids to latches on which threads wait for replies. */ + /** + * Holds a map from message ids to latches on which threads wait for replies. + */ private Map trafficLights = new HashMap(); - /** Used to indicate that the ping loop should print out whenever it pings. */ + /** + * Used to indicate that the ping loop should print out whenever it pings. + */ protected boolean _verbose = false; protected Session _consumerSession; - protected PingPongProducer(String brokerDetails, String username, String password, String virtualpath, - boolean transacted) + private PingPongProducer(String brokerDetails, String username, String password, String virtualpath, + boolean transacted, boolean persistent, int messageSize, boolean verbose, + boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, + int batchSize) throws Exception { // Create a connection to the broker. @@ -132,6 +158,18 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Create transactional or non-transactional sessions, based on the command line arguments. setProducerSession((Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE)); _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + + _persistent = persistent; + _messageSize = messageSize; + _verbose = verbose; + + // Set failover interrupts + _failAfterCommit = afterCommit; + _failBeforeCommit = beforeCommit; + _failAfterSend = afterSend; + _failBeforeSend = beforeSend; + _batchSize = batchSize; + _sentMessages = 0; } /** @@ -142,31 +180,39 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * @param password * @param virtualpath * @param transacted - * @param persistent - * @param messageSize - * @param verbose - * * @throws Exception All allowed to fall through. This is only test code... */ public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, String queueName, - String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose) - throws Exception + String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, + boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, + int batchSize, int queueCount) + throws Exception { - this(brokerDetails, username, password, virtualpath, transacted); + this(brokerDetails, username, password, virtualpath, transacted, persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, batchSize); - _pingQueue = new AMQQueue(queueName); - _persistent = persistent; - _messageSize = messageSize; - _verbose = verbose; - - // Create producer and the consumer - createProducer(); - createConsumer(selector); + if (queueName != null) + { + _pingQueue = new AMQQueue(queueName); + // Create producer and the consumer + createProducer(); + createConsumer(selector); + } + else if (queueCount > 0) + { + _queueCount = queueCount; + } + else + { + _logger.error("Queue Count is zero and no queueName specified. One must be set."); + throw new IllegalArgumentException("Queue Count is zero and no queueName specified. One must be set."); + } } /** * Creates the producer to send the pings on. If the tests are with nultiple queues, then producer * is created with null destination, so that any destination can be specified while sending + * * @throws JMSException */ public void createProducer() throws JMSException @@ -189,6 +235,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, /** * Creates the temporary queue to listen to the responses + * * @param selector * @throws JMSException */ @@ -204,6 +251,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, /** * Creates consumer instances for each queue. This is used when test is being done with multiple queues. + * * @param selector * @throws JMSException */ @@ -234,7 +282,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, /** * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs * to be started to bounce the pings back again. - * + *

    *

    The command line takes from 2 to 4 arguments: *

    *
    brokerDetails The broker connection string. @@ -251,7 +299,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, if (args.length < 2) { System.err.println("Usage: TestPingPublisher [verbose (true/false)] " + - "[transacted (true/false)] [persistent (true/false)] [message size in bytes]"); + "[transacted (true/false)] [persistent (true/false)] [message size in bytes]"); System.exit(0); } @@ -261,10 +309,46 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, boolean transacted = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; boolean persistent = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; + int batchSize = (args.length >= 7) ? Integer.parseInt(args[6]) : 1; + + boolean afterCommit = false; + boolean beforeCommit = false; + boolean afterSend = false; + boolean beforeSend = false; + + for (String arg : args) + { + if (arg.startsWith("failover:")) + { + //failover:: + String[] parts = arg.split(":"); + if (parts.length == 3) + { + if (parts[2].equals("commit")) + { + afterCommit = parts[1].equals("after"); + beforeCommit = parts[1].equals("before"); + } + + if (parts[2].equals("send")) + { + afterSend = parts[1].equals("after"); + beforeSend = parts[1].equals("before"); + } + } + else + { + System.out.println("Unrecognized failover request:" + arg); + } + } + } // Create a ping producer to handle the request/wait/reply cycle. _pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, null, transacted, - persistent, messageSize, verbose); + persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, + batchSize, 0); + _pingProducer.getConnection().start(); // Run a few priming pings to remove warm up time from test results. @@ -287,7 +371,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * this a few times, in order to prime the JVMs JIT compilation. * * @param x The number of priming loops to run. - * * @throws JMSException All underlying exceptions are allowed to fall through. */ public void prime(int x) throws JMSException @@ -296,15 +379,18 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, { // Create and send a small message. Message first = getTestMessage(_replyQueue, 0, false); - _producer.send(first); - commitTx(getProducerSession()); + + sendMessage(first); + + commitTx(); try { Thread.sleep(100); } catch (InterruptedException ignore) - { } + { + } } } @@ -365,10 +451,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * @param message The message to send. * @param numPings The number of ping messages to send. * @param timeout The timeout in milliseconds. - * * @return The number of replies received. This may be less than the number sent if the timeout terminated the * wait for all prematurely. - * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ public int pingAndWaitForReply(Message message, int numPings, long timeout) throws JMSException, InterruptedException @@ -394,13 +478,13 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, { // Re-timestamp the message. message.setLongProperty("timestamp", System.currentTimeMillis()); - _producer.send(message); + sendMessage(message); } } // Commit the transaction if running in transactional mode. This must happen now, rather than at the end of // this method, as the message will not be sent until the transaction is committed. - commitTx(getProducerSession()); + commitTx(); // Keep the messageId to correlate with the reply. //String messageId = message.getJMSMessageID(); @@ -429,7 +513,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, /** * When the test is being performed with multiple queues, then this method will be used, which has a loop to - * pick up the next queue from the queues list and sends message to it. + * pick up the next queue from the queues list and sends message to it. + * * @param message * @param numPings * @throws JMSException @@ -441,31 +526,30 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, { // Re-timestamp the message. message.setLongProperty("timestamp", System.currentTimeMillis()); - _producer.send(getQueue(queueIndex++), message); + + sendMessage(getQueue(queueIndex++), message); // reset the counter to get the first queue - if (queueIndex == getQueueCount() -1) + if (queueIndex == getQueueCount() - 1) { queueIndex = 0; } } } - + /** * Sends the specified ping message but does not wait for a correlating reply. * * @param message The message to send. * @param numPings The number of pings to send. - * * @return The reply, or null if no reply arrives before the timeout. - * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ public void pingNoWaitForReply(Message message, int numPings) throws JMSException, InterruptedException { for (int i = 0; i < numPings; i++) { - _producer.send(message); + sendMessage(message); if (_verbose) { @@ -474,7 +558,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } // Commit the transaction if running in transactional mode, to force the send now. - commitTx(getProducerSession()); + commitTx(); } /** @@ -524,19 +608,21 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, public static class FailoverNotifier implements ConnectionListener { public void bytesSent(long count) - { } + { + } public void bytesReceived(long count) - { } + { + } public boolean preFailover(boolean redirect) { - return true; + return true; //Allow failover } public boolean preResubscribe() { - return true; + return true; // Allow resubscription } public void failoverComplete() -- cgit v1.2.1 From b091dc5a2f7f36ce2d7cd825aaf963adfbc109d1 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Tue, 23 Jan 2007 10:15:24 +0000 Subject: Test modified to take arguments with - options git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@498974 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/ping/TestPingItself.java | 156 ++++++++++++++------- .../main/java/org/apache/qpid/topic/Config.java | 48 +++++-- 2 files changed, 146 insertions(+), 58 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java index 579816870f..5a1ec691a7 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java @@ -17,22 +17,13 @@ */ package org.apache.qpid.ping; -import org.apache.qpid.requestreply.PingPongProducer; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.jms.Session; -import org.apache.qpid.jms.MessageProducer; import org.apache.log4j.Logger; +import org.apache.qpid.requestreply.PingPongProducer; +import org.apache.qpid.topic.Config; import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.ObjectMessage; -import javax.jms.Connection; -import javax.jms.DeliveryMode; -import javax.jms.Queue; -import java.net.InetAddress; -import java.util.List; -import java.util.ArrayList; /** * This class is used to test sending and receiving messages to (pingQueue) and from a queue (replyQueue). @@ -44,6 +35,26 @@ public class TestPingItself extends PingPongProducer { private static final Logger _logger = Logger.getLogger(TestPingItself.class); + /** + * This creates a client for pinging to a Queue. There will be one producer and one consumer instance. Consumer + * listening to the same Queue, producer is sending to + * @param brokerDetails + * @param username + * @param password + * @param virtualpath + * @param queueName + * @param selector + * @param transacted + * @param persistent + * @param messageSize + * @param verbose + * @param afterCommit + * @param beforeCommit + * @param afterSend + * @param beforeSend + * @param batchSize + * @throws Exception + */ public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String queueName, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, @@ -54,6 +65,26 @@ public class TestPingItself extends PingPongProducer verbose, afterCommit, beforeCommit, afterSend, beforeSend, batchSize, 0); } + /** + * This creats a client for tests with multiple queues. Creates as many consumer instances as there are queues, + * each listening to a Queue. A producer is created which picks up a queue from the list of queues to send message. + * @param brokerDetails + * @param username + * @param password + * @param virtualpath + * @param selector + * @param transacted + * @param persistent + * @param messageSize + * @param verbose + * @param afterCommit + * @param beforeCommit + * @param afterSend + * @param beforeSend + * @param batchSize + * @param queueCount + * @throws Exception + */ public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, @@ -73,10 +104,10 @@ public class TestPingItself extends PingPongProducer createProducer(); } - @Override /** - * Sets the replyQueue to be the same as ping queue. + * Sets the replyQueue to be the same as ping queue. */ + @Override public void createConsumer(String selector) throws JMSException { // Create a message consumer to get the replies with and register this to be called back by it. @@ -86,36 +117,24 @@ public class TestPingItself extends PingPongProducer } /** - * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs - * to be started to bounce the pings back again. - *

    - *

    The command line takes from 2 to 4 arguments: - *

    - *
    brokerDetails The broker connection string. - *
    virtualPath The virtual path. - *
    transacted A boolean flag, telling this client whether or not to use transactions. - *
    size The size of ping messages to use, in bytes. - *
    - * + * Starts a ping-pong loop running from the command line. * @param args The command line arguments as defined above. */ public static void main(String[] args) throws Exception { // Extract the command line. - if (args.length < 2) - { - System.err.println("Usage: TestPingPublisher [verbose (true/false)] " + - "[transacted (true/false)] [persistent (true/false)] [message size in bytes]"); - System.exit(0); - } - - String brokerDetails = args[0]; - String virtualpath = args[1]; - boolean verbose = (args.length >= 3) ? Boolean.parseBoolean(args[2]) : true; - boolean transacted = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; - boolean persistent = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; - int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; - int batchSize = (args.length >= 7) ? Integer.parseInt(args[6]) : 1; + Config config = new Config(); + config.setOptions(args); + + String brokerDetails = config.getHost() + ":" + config.getPort(); + String virtualpath = "/test"; + boolean verbose = false; + boolean transacted = config.isTransacted(); + boolean persistent = config.usePersistentMessages(); + int messageSize = config.getPayload() != 0 ? config.getPayload() : DEFAULT_MESSAGE_SIZE; + int messageCount = config.getMessages(); + int queueCount = config.getQueueCount(); + int batchSize = config.getBatchSize() != 0 ? config.getBatchSize() : BATCH_SIZE; String queue = "ping_" + System.currentTimeMillis(); _logger.info("Queue:" + queue + ", Transacted:" + transacted + ", persistent:" + persistent + @@ -154,24 +173,65 @@ public class TestPingItself extends PingPongProducer } } + TestPingItself pingItself = null; // Create a ping producer to handle the request/wait/reply cycle. - TestPingItself pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, - transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, - batchSize); + if (queueCount > 1) + { + pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, null, + transacted, persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, + batchSize, queueCount); + } + else + { + pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, + transacted, persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, + batchSize); + } + pingItself.getConnection().start(); - // Run a few priming pings to remove warm up time from test results. - pingItself.prime(PRIMING_LOOPS); // Create a shutdown hook to terminate the ping-pong producer. Runtime.getRuntime().addShutdownHook(pingItself.getShutdownHook()); // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. pingItself.getConnection().setExceptionListener(pingItself); - // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. - Thread pingThread = new Thread(pingItself); - pingThread.run(); - pingThread.join(); + if ((queueCount > 1) || (messageCount > 0)) + { + ObjectMessage msg = pingItself.getTestMessage(null, messageSize, persistent); + + // Send the message and wait for a reply. + int numReplies = pingItself.pingAndWaitForReply(msg, messageCount, TIMEOUT); + + _logger.info(("Messages Sent = " + messageCount + ", MessagesReceived = " + numReplies)); + } + else + { + // set the message count to 0 to run this loop + // Run a few priming pings to remove warm up time from test results. + pingItself.prime(PRIMING_LOOPS); + + _logger.info("Running the infinite loop and pinging the broker..."); + // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. + Thread pingThread = new Thread(pingItself); + pingThread.run(); + pingThread.join(); + } + pingItself.getConnection().close(); + } + + private static void usage() + { + System.err.println("Usage: TestPingPublisher \n" + + "-host : broker host" + + "-port : broker port" + + "-transacted : (true/false). Default is false" + + "-persistent : (true/false). Default is false" + + "-payload : paylaod size. Default is 0" + + "-queues : no of queues" + + "-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)"); + System.exit(0); } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java index bb740f9094..439e1ee2ca 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java @@ -22,14 +22,12 @@ package org.apache.qpid.topic; import org.apache.qpid.client.AMQSession; import org.apache.qpid.config.ConnectorConfig; -import org.apache.qpid.config.ConnectionFactoryInitialiser; import org.apache.qpid.config.Connector; import org.apache.qpid.config.AbstractConfig; import javax.jms.Connection; -import javax.jms.ConnectionFactory; -class Config extends AbstractConfig implements ConnectorConfig +public class Config extends AbstractConfig implements ConnectorConfig { private String host = "localhost"; @@ -46,22 +44,25 @@ class Config extends AbstractConfig implements ConnectorConfig private String clientId; private String subscriptionId; private boolean persistent; + private boolean transacted; + private int noOfQueues; + private int batchSize; public Config() { } - int getAckMode() + public int getAckMode() { return ackMode; } - void setPayload(int payload) + public void setPayload(int payload) { this.payload = payload; } - int getPayload() + public int getPayload() { return payload; } @@ -81,11 +82,21 @@ class Config extends AbstractConfig implements ConnectorConfig this.messages = messages; } - int getMessages() + public int getMessages() { return messages; } + public int getBatchSize() + { + return batchSize; + } + + public int getQueueCount() + { + return noOfQueues; + } + public String getHost() { return host; @@ -141,21 +152,26 @@ class Config extends AbstractConfig implements ConnectorConfig this.delay = delay; } - String getClientId() + public String getClientId() { return clientId; } - String getSubscriptionId() + public String getSubscriptionId() { return subscriptionId; } - boolean usePersistentMessages() + public boolean usePersistentMessages() { return persistent; } + public boolean isTransacted() + { + return transacted; + } + public void setOption(String key, String value) { if("-host".equalsIgnoreCase(key)) @@ -217,6 +233,18 @@ class Config extends AbstractConfig implements ConnectorConfig { persistent = "true".equalsIgnoreCase(value); } + else if("-transacted".equalsIgnoreCase(key)) + { + transacted = "true".equalsIgnoreCase(value); + } + else if ("-queues".equalsIgnoreCase(key)) + { + noOfQueues = parseInt("Bad queues count", value); + } + else if ("-batchsize".equalsIgnoreCase(key)) + { + batchSize = parseInt("Bad batch size", value); + } else { System.out.println("Ignoring unrecognised option: " + key); -- cgit v1.2.1 From 5d9f6b3443c51f437f2b9c0f997e2d26b492dcc6 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 23 Jan 2007 10:55:00 +0000 Subject: FailOver added flag FAIL_ONCE so that only the first call is stopped for failover.. the default. Updated POM with Failover Tests git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@498984 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/AbstractPingProducer.java | 31 +++++++++++--- .../java/org/apache/qpid/ping/TestPingItself.java | 47 +++++++++++++--------- .../org/apache/qpid/ping/TestPingProducer.java | 13 ++++-- .../apache/qpid/requestreply/PingPongProducer.java | 26 ++++++------ 4 files changed, 76 insertions(+), 41 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java index 4cca77a70e..999f4c9100 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java @@ -78,6 +78,7 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene protected boolean _failAfterCommit = false; protected boolean _failBeforeSend = false; protected boolean _failAfterSend = false; + protected boolean _failOnce = true; protected int _sentMessages = 0; protected int _batchSize = 1; @@ -257,12 +258,28 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene { if ((++_sentMessages % _batchSize) == 0) { + _logger.trace("Batch time reached"); + if (_failAfterSend) + { + if (_failOnce) + { + _failAfterSend = false; + } + _logger.trace("Failing After Send"); + doFailover(); + } + + if (session.getTransacted()) { try { if (_failBeforeCommit) { + if (_failOnce) + { + _failBeforeCommit = false; + } _logger.trace("Failing Before Commit"); doFailover(); } @@ -271,6 +288,10 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene if (_failAfterCommit) { + if (_failOnce) + { + _failAfterCommit = false; + } _logger.trace("Failing After Commit"); doFailover(); } @@ -312,6 +333,10 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene { if (_failBeforeSend) { + if (_failOnce) + { + _failBeforeSend = false; + } _logger.trace("Failing Before Send"); doFailover(); } @@ -325,11 +350,7 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene _producer.send(q, message); } - if (_failAfterSend) - { - _logger.trace("Failing After Send"); - doFailover(); - } + commitTx(); } protected void doFailover(String broker) diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java index 5a1ec691a7..6bfc2af541 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java @@ -38,6 +38,7 @@ public class TestPingItself extends PingPongProducer /** * This creates a client for pinging to a Queue. There will be one producer and one consumer instance. Consumer * listening to the same Queue, producer is sending to + * * @param brokerDetails * @param username * @param password @@ -57,17 +58,18 @@ public class TestPingItself extends PingPongProducer */ public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String queueName, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, - boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, + boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize) throws Exception { super(brokerDetails, username, password, virtualpath, queueName, selector, transacted, persistent, messageSize, - verbose, afterCommit, beforeCommit, afterSend, beforeSend, batchSize, 0); + verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, 0); } /** * This creats a client for tests with multiple queues. Creates as many consumer instances as there are queues, * each listening to a Queue. A producer is created which picks up a queue from the list of queues to send message. + * * @param brokerDetails * @param username * @param password @@ -87,12 +89,12 @@ public class TestPingItself extends PingPongProducer */ public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, - boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, + boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, int queueCount) throws Exception { super(brokerDetails, username, password, virtualpath, null, null, transacted, persistent, messageSize, - verbose, afterCommit, beforeCommit, afterSend, beforeSend, batchSize, queueCount); + verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, queueCount); createQueues(queueCount); @@ -117,7 +119,8 @@ public class TestPingItself extends PingPongProducer } /** - * Starts a ping-pong loop running from the command line. + * Starts a ping-pong loop running from the command line. + * * @param args The command line arguments as defined above. */ public static void main(String[] args) throws Exception @@ -145,6 +148,7 @@ public class TestPingItself extends PingPongProducer boolean beforeCommit = false; boolean afterSend = false; boolean beforeSend = false; + boolean failOnce = false; for (String arg : args) { @@ -165,6 +169,11 @@ public class TestPingItself extends PingPongProducer afterSend = parts[1].equals("after"); beforeSend = parts[1].equals("before"); } + if (parts[1].equals("once")) + { + failOnce = true; + } + } else { @@ -178,18 +187,18 @@ public class TestPingItself extends PingPongProducer if (queueCount > 1) { pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, null, - transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, - batchSize, queueCount); + transacted, persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, failOnce, + batchSize, queueCount); } else { pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, - transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, - batchSize); + transacted, persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, failOnce, + batchSize); } - + pingItself.getConnection().start(); // Create a shutdown hook to terminate the ping-pong producer. @@ -225,13 +234,13 @@ public class TestPingItself extends PingPongProducer private static void usage() { System.err.println("Usage: TestPingPublisher \n" + - "-host : broker host" + - "-port : broker port" + - "-transacted : (true/false). Default is false" + - "-persistent : (true/false). Default is false" + - "-payload : paylaod size. Default is 0" + - "-queues : no of queues" + - "-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)"); + "-host : broker host" + + "-port : broker port" + + "-transacted : (true/false). Default is false" + + "-persistent : (true/false). Default is false" + + "-payload : paylaod size. Default is 0" + + "-queues : no of queues" + + "-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)"); System.exit(0); } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java index e53d7bb521..adf1c4dd9b 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java @@ -88,7 +88,8 @@ class TestPingProducer extends AbstractPingProducer public TestPingProducer(String brokerDetails, String username, String password, String virtualpath, String queueName, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, - boolean beforeCommit, boolean afterSend, boolean beforeSend,int batchSize) throws Exception + boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, + int batchSize) throws Exception { // Create a connection to the broker. InetAddress address = InetAddress.getLocalHost(); @@ -115,6 +116,7 @@ class TestPingProducer extends AbstractPingProducer _failBeforeSend = beforeSend; _sentMessages = 0; _batchSize = batchSize; + _failOnce = failOnce; } /** @@ -129,7 +131,7 @@ class TestPingProducer extends AbstractPingProducer if (args.length < 2) { System.err.println( - "Usage: TestPingPublisher "+ + "Usage: TestPingPublisher " + "[ "); System.exit(0); } @@ -147,6 +149,7 @@ class TestPingProducer extends AbstractPingProducer boolean beforeCommit = false; boolean afterSend = false; boolean beforeSend = false; + boolean failOnce = false; for (String arg : args) { @@ -167,6 +170,10 @@ class TestPingProducer extends AbstractPingProducer afterSend = parts[1].equals("after"); beforeSend = parts[1].equals("before"); } + if (parts[1].equals("once")) + { + failOnce = true; + } } else { @@ -178,7 +185,7 @@ class TestPingProducer extends AbstractPingProducer // Create a ping producer to generate the pings. _pingProducer = new TestPingProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, + afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize); // Start the connection running. diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 3c3e31dd55..c0a041037d 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -145,7 +145,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, private PingPongProducer(String brokerDetails, String username, String password, String virtualpath, boolean transacted, boolean persistent, int messageSize, boolean verbose, - boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, + boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize) throws Exception { @@ -168,6 +168,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _failBeforeCommit = beforeCommit; _failAfterSend = afterSend; _failBeforeSend = beforeSend; + _failOnce = failOnce; _batchSize = batchSize; _sentMessages = 0; } @@ -184,12 +185,12 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, */ public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, String queueName, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, - boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, + boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, int queueCount) throws Exception { this(brokerDetails, username, password, virtualpath, transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, batchSize); + afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize); if (queueName != null) { @@ -311,16 +312,18 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; int batchSize = (args.length >= 7) ? Integer.parseInt(args[6]) : 1; + boolean afterCommit = false; boolean beforeCommit = false; boolean afterSend = false; boolean beforeSend = false; + boolean failOnce = false; for (String arg : args) { if (arg.startsWith("failover:")) { - //failover:: + //failover:: | failover:once String[] parts = arg.split(":"); if (parts.length == 3) { @@ -335,6 +338,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, afterSend = parts[1].equals("after"); beforeSend = parts[1].equals("before"); } + if (parts[1].equals("once")) + { + failOnce = true; + } } else { @@ -346,7 +353,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Create a ping producer to handle the request/wait/reply cycle. _pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, null, transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, + afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, 0); _pingProducer.getConnection().start(); @@ -382,8 +389,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, sendMessage(first); - commitTx(); - try { Thread.sleep(100); @@ -482,10 +487,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } } - // Commit the transaction if running in transactional mode. This must happen now, rather than at the end of - // this method, as the message will not be sent until the transaction is committed. - commitTx(); - // Keep the messageId to correlate with the reply. //String messageId = message.getJMSMessageID(); if (_verbose) @@ -556,9 +557,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _logger.info(timestampFormatter.format(new Date()) + ": Pinged at."); } } - - // Commit the transaction if running in transactional mode, to force the send now. - commitTx(); } /** -- cgit v1.2.1 From f33d7d973c3d55a30fb94c91e721a865ec5689ab Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Tue, 23 Jan 2007 14:41:33 +0000 Subject: updated the test for testing with multiple threads git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499036 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/ping/TestPingItself.java | 78 ++++++---------------- .../apache/qpid/requestreply/PingPongProducer.java | 50 +++++++------- 2 files changed, 44 insertions(+), 84 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java index 6bfc2af541..4cbe9e8585 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java @@ -36,9 +36,10 @@ public class TestPingItself extends PingPongProducer private static final Logger _logger = Logger.getLogger(TestPingItself.class); /** - * This creates a client for pinging to a Queue. There will be one producer and one consumer instance. Consumer - * listening to the same Queue, producer is sending to - * + * If queueCount is <= 1 : There will be one Queue and one consumer instance for the test + * If queueCount is > 1 : This creats a client for tests with multiple queues. Creates as many consumer instances + * as there are queues, each listening to a Queue. A producer is created which picks up a queue from + * the list of queues to send message * @param brokerDetails * @param username * @param password @@ -53,57 +54,31 @@ public class TestPingItself extends PingPongProducer * @param beforeCommit * @param afterSend * @param beforeSend - * @param batchSize - * @throws Exception - */ - public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String queueName, - String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, - boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, - int batchSize) - throws Exception - { - super(brokerDetails, username, password, virtualpath, queueName, selector, transacted, persistent, messageSize, - verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, 0); - } - - /** - * This creats a client for tests with multiple queues. Creates as many consumer instances as there are queues, - * each listening to a Queue. A producer is created which picks up a queue from the list of queues to send message. - * - * @param brokerDetails - * @param username - * @param password - * @param virtualpath - * @param selector - * @param transacted - * @param persistent - * @param messageSize - * @param verbose - * @param afterCommit - * @param beforeCommit - * @param afterSend - * @param beforeSend + * @param failOnce * @param batchSize * @param queueCount * @throws Exception */ - public TestPingItself(String brokerDetails, String username, String password, String virtualpath, + public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String queueName, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, int queueCount) throws Exception { - super(brokerDetails, username, password, virtualpath, null, null, transacted, persistent, messageSize, + super(brokerDetails, username, password, virtualpath, queueName, selector, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, queueCount); - createQueues(queueCount); + if (queueCount > 1) + { + createQueues(queueCount); - _persistent = persistent; - _messageSize = messageSize; - _verbose = verbose; + _persistent = persistent; + _messageSize = messageSize; + _verbose = verbose; - createConsumers(selector); - createProducer(); + createConsumers(selector); + createProducer(); + } } /** @@ -136,7 +111,7 @@ public class TestPingItself extends PingPongProducer boolean persistent = config.usePersistentMessages(); int messageSize = config.getPayload() != 0 ? config.getPayload() : DEFAULT_MESSAGE_SIZE; int messageCount = config.getMessages(); - int queueCount = config.getQueueCount(); + int queueCount = config.getQueueCount() != 0 ? config.getQueueCount() : 1; int batchSize = config.getBatchSize() != 0 ? config.getBatchSize() : BATCH_SIZE; String queue = "ping_" + System.currentTimeMillis(); @@ -182,22 +157,11 @@ public class TestPingItself extends PingPongProducer } } - TestPingItself pingItself = null; // Create a ping producer to handle the request/wait/reply cycle. - if (queueCount > 1) - { - pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, null, - transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, failOnce, - batchSize, queueCount); - } - else - { - pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, - transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, failOnce, - batchSize); - } + TestPingItself pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, + transacted, persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, failOnce, + batchSize, queueCount); pingItself.getConnection().start(); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index c0a041037d..6ff0af214b 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -93,10 +93,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, */ protected static final int BATCH_SIZE = 100; - /** - * Keeps track of the ping producer instance used in the run loop. - */ - private static PingPongProducer _pingProducer; protected static final int PREFETCH = 100; protected static final boolean NO_LOCAL = true; protected static final boolean EXCLUSIVE = false; @@ -109,7 +105,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, /** * A source for providing sequential unique correlation ids. */ - private AtomicLong idGenerator = new AtomicLong(0L); + private static AtomicLong idGenerator = new AtomicLong(0L); /** * Holds the queue to send the ping replies to. @@ -134,7 +130,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, /** * Holds a map from message ids to latches on which threads wait for replies. */ - private Map trafficLights = new HashMap(); + private static Map trafficLights = new HashMap(); /** * Used to indicate that the ping loop should print out whenever it pings. @@ -192,21 +188,21 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, this(brokerDetails, username, password, virtualpath, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize); - if (queueName != null) - { - _pingQueue = new AMQQueue(queueName); - // Create producer and the consumer - createProducer(); - createConsumer(selector); - } - else if (queueCount > 0) - { - _queueCount = queueCount; - } - else + _queueCount = queueCount; + if (queueCount <= 1) { - _logger.error("Queue Count is zero and no queueName specified. One must be set."); - throw new IllegalArgumentException("Queue Count is zero and no queueName specified. One must be set."); + if (queueName != null) + { + _pingQueue = new AMQQueue(queueName); + // Create producer and the consumer + createProducer(); + createConsumer(selector); + } + else + { + _logger.error("Queue Name is not specified"); + throw new IllegalArgumentException("Queue Name is not specified"); + } } } @@ -351,23 +347,23 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } // Create a ping producer to handle the request/wait/reply cycle. - _pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, null, transacted, + PingPongProducer pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, null, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, 0); - _pingProducer.getConnection().start(); + pingProducer.getConnection().start(); // Run a few priming pings to remove warm up time from test results. - _pingProducer.prime(PRIMING_LOOPS); + pingProducer.prime(PRIMING_LOOPS); // Create a shutdown hook to terminate the ping-pong producer. - Runtime.getRuntime().addShutdownHook(_pingProducer.getShutdownHook()); + Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. - _pingProducer.getConnection().setExceptionListener(_pingProducer); + pingProducer.getConnection().setExceptionListener(pingProducer); // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. - Thread pingThread = new Thread(_pingProducer); + Thread pingThread = new Thread(pingProducer); pingThread.run(); pingThread.join(); } @@ -502,7 +498,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, if ((numReplies < numPings) && _verbose) { - _logger.info("Timed out before all replies received on id, " + messageCorrelationId); + _logger.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); } else if (_verbose) { -- cgit v1.2.1 From 0bf51c656998eea8c0e4a2f6cdb6b588b23f6cc8 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Tue, 23 Jan 2007 17:08:03 +0000 Subject: (Patch submitted by Rupert Smith) Added the ability to limit the rate at which messages are sent by the ping tests. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499083 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/AbstractPingProducer.java | 159 +++++----- .../java/org/apache/qpid/ping/TestPingItself.java | 73 +++-- .../org/apache/qpid/ping/TestPingProducer.java | 23 +- .../main/java/org/apache/qpid/ping/Throttle.java | 3 +- .../apache/qpid/requestreply/PingPongBouncer.java | 54 ++-- .../apache/qpid/requestreply/PingPongProducer.java | 346 ++++++++++++--------- .../main/java/org/apache/qpid/topic/Config.java | 10 + 7 files changed, 365 insertions(+), 303 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java index 999f4c9100..33207790e7 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java @@ -1,10 +1,10 @@ package org.apache.qpid.ping; +import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.io.IOException; -import java.util.List; import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import javax.jms.*; @@ -15,12 +15,12 @@ import javax.jms.MessageProducer; import org.apache.log4j.Logger; import org.apache.qpid.client.AMQNoConsumersException; -import org.apache.qpid.client.BasicMessageProducer; import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.BasicMessageProducer; import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.jms.*; import org.apache.qpid.jms.Session; -import org.apache.qpid.framing.AMQShortString; /** * This abstract class captures functionality that is common to all ping producers. It provides functionality to @@ -46,6 +46,9 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene */ protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); + /** This id generator is used to generate ids to append to the queue name to ensure that queues are unique. */ + private static AtomicInteger _queueSequenceID = new AtomicInteger(); + /** * Used to tell the ping loop when to terminate, it only runs while this is true. */ @@ -61,12 +64,11 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene */ private Session _producerSession; - /** - * holds the no of queues the tests will be using to send messages. By default it will be 1 + * Holds the number of queues the tests will be using to send messages. By default it will be 1 */ - protected int _queueCount; - private static AtomicInteger _queueSequenceID = new AtomicInteger(); + protected int _queueCount = 1; + private List _queues = new ArrayList(); /** @@ -80,9 +82,8 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene protected boolean _failAfterSend = false; protected boolean _failOnce = true; - protected int _sentMessages = 0; - protected int _batchSize = 1; - + /** Holds the number of sends that should be performed in every transaction when using transactions. */ + protected int _txBatchSize = 1; /** * Convenience method for a short pause. @@ -98,11 +99,14 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene Thread.sleep(sleepTime); } catch (InterruptedException ie) - { - } + { } } } + /** + * Implementations should provide this method to perform a single ping cycle (which may send many messages). The + * run loop will repeatedly call this method until the publish flag is set to false. + */ public abstract void pingLoop(); /** @@ -110,8 +114,10 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene * * @param replyQueue The reply-to destination for the message. * @param messageSize The desired size of the message in bytes. + * * @return A freshly generated test message. - * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. + * + * @throws JMSException All underlying JMSException are allowed to fall through. */ public ObjectMessage getTestMessage(Queue replyQueue, int messageSize, boolean persistent) throws JMSException { @@ -183,12 +189,12 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene public Thread getShutdownHook() { return new Thread(new Runnable() - { - public void run() { - stop(); - } - }); + public void run() + { + stop(); + } + }); } public Connection getConnection() @@ -211,12 +217,6 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene this._producerSession = session; } - - protected void commitTx() throws JMSException - { - commitTx(getProducerSession()); - } - public int getQueueCount() { return _queueCount; @@ -227,6 +227,11 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene this._queueCount = queueCount; } + protected void commitTx() throws JMSException + { + commitTx(getProducerSession()); + } + /** * Creates queues dynamically and adds to the queues list. This is when the test is being done with * multiple queues. @@ -237,7 +242,8 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene { for (int i = 0; i < queueCount; i++) { - AMQShortString name = new AMQShortString("Queue_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); + AMQShortString name = + new AMQShortString("Queue_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); AMQQueue queue = new AMQQueue(name, name, false, false, false); _queues.add(queue); @@ -256,69 +262,69 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene */ protected void commitTx(Session session) throws JMSException { - if ((++_sentMessages % _batchSize) == 0) + _logger.trace("Batch time reached"); + if (_failAfterSend) { - _logger.trace("Batch time reached"); - if (_failAfterSend) + if (_failOnce) { - if (_failOnce) - { - _failAfterSend = false; - } - _logger.trace("Failing After Send"); - doFailover(); + _failAfterSend = false; } + _logger.trace("Failing After Send"); + doFailover(); + } - if (session.getTransacted()) + if (session.getTransacted()) + { + try { - try + if (_failBeforeCommit) { - if (_failBeforeCommit) + if (_failOnce) { - if (_failOnce) - { - _failBeforeCommit = false; - } - _logger.trace("Failing Before Commit"); - doFailover(); + _failBeforeCommit = false; } - session.commit(); + _logger.trace("Failing Before Commit"); + doFailover(); + } + + session.commit(); - if (_failAfterCommit) + if (_failAfterCommit) + { + if (_failOnce) { - if (_failOnce) - { - _failAfterCommit = false; - } - _logger.trace("Failing After Commit"); - doFailover(); + _failAfterCommit = false; } - _logger.trace("Session Commited."); + + _logger.trace("Failing After Commit"); + doFailover(); } - catch (JMSException e) - { - _logger.trace("JMSException on commit:" + e.getMessage(), e); - // Warn that the bounce back client is not available. - if (e.getLinkedException() instanceof AMQNoConsumersException) - { - _logger.debug("No consumers on queue."); - } + _logger.trace("Session Commited."); + } + catch (JMSException e) + { + _logger.trace("JMSException on commit:" + e.getMessage(), e); - try - { - session.rollback(); - _logger.trace("Message rolled back."); - } - catch (JMSException jmse) - { - _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); + // Warn that the bounce back client is not available. + if (e.getLinkedException() instanceof AMQNoConsumersException) + { + _logger.debug("No consumers on queue."); + } - // Both commit and rollback failed. Throw the rollback exception. - throw jmse; - } + try + { + session.rollback(); + _logger.trace("Message rolled back."); + } + catch (JMSException jmse) + { + _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); + + // Both commit and rollback failed. Throw the rollback exception. + throw jmse; } } } @@ -337,6 +343,7 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene { _failBeforeSend = false; } + _logger.trace("Failing Before Send"); doFailover(); } @@ -361,8 +368,8 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene System.in.read(); } catch (IOException e) - { - } + { } + System.out.println("Continuing."); } @@ -374,8 +381,8 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene System.in.read(); } catch (IOException e) - { - } + { } + System.out.println("Continuing."); } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java index 4cbe9e8585..35320d8b55 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java @@ -17,14 +17,15 @@ */ package org.apache.qpid.ping; -import org.apache.log4j.Logger; -import org.apache.qpid.requestreply.PingPongProducer; -import org.apache.qpid.topic.Config; - import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.ObjectMessage; +import org.apache.log4j.Logger; + +import org.apache.qpid.requestreply.PingPongProducer; +import org.apache.qpid.topic.Config; + /** * This class is used to test sending and receiving messages to (pingQueue) and from a queue (replyQueue). * The producer and consumer created by this test send and receive messages to and from the same Queue. ie. @@ -62,11 +63,10 @@ public class TestPingItself extends PingPongProducer public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String queueName, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, - int batchSize, int queueCount) - throws Exception + int batchSize, int queueCount, int rate) throws Exception { super(brokerDetails, username, password, virtualpath, queueName, selector, transacted, persistent, messageSize, - verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, queueCount); + verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, queueCount, rate); if (queueCount > 1) { @@ -81,18 +81,6 @@ public class TestPingItself extends PingPongProducer } } - /** - * Sets the replyQueue to be the same as ping queue. - */ - @Override - public void createConsumer(String selector) throws JMSException - { - // Create a message consumer to get the replies with and register this to be called back by it. - setReplyQueue(getPingQueue()); - MessageConsumer consumer = getConsumerSession().createConsumer(getReplyQueue(), PREFETCH, false, EXCLUSIVE, selector); - consumer.setMessageListener(this); - } - /** * Starts a ping-pong loop running from the command line. * @@ -109,15 +97,15 @@ public class TestPingItself extends PingPongProducer boolean verbose = false; boolean transacted = config.isTransacted(); boolean persistent = config.usePersistentMessages(); - int messageSize = config.getPayload() != 0 ? config.getPayload() : DEFAULT_MESSAGE_SIZE; + int messageSize = (config.getPayload() != 0) ? config.getPayload() : DEFAULT_MESSAGE_SIZE; int messageCount = config.getMessages(); - int queueCount = config.getQueueCount() != 0 ? config.getQueueCount() : 1; - int batchSize = config.getBatchSize() != 0 ? config.getBatchSize() : BATCH_SIZE; + int queueCount = (config.getQueueCount() != 0) ? config.getQueueCount() : 1; + int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : BATCH_SIZE; + int rate = (config.getRate() != 0) ? config.getRate() : 0; String queue = "ping_" + System.currentTimeMillis(); - _logger.info("Queue:" + queue + ", Transacted:" + transacted + ", persistent:" + persistent + - ",MessageSize:" + messageSize + " bytes"); - + _logger.info("Queue:" + queue + ", Transacted:" + transacted + ", persistent:" + persistent + ",MessageSize:" + + messageSize + " bytes"); boolean afterCommit = false; boolean beforeCommit = false; @@ -144,6 +132,7 @@ public class TestPingItself extends PingPongProducer afterSend = parts[1].equals("after"); beforeSend = parts[1].equals("before"); } + if (parts[1].equals("once")) { failOnce = true; @@ -158,10 +147,10 @@ public class TestPingItself extends PingPongProducer } // Create a ping producer to handle the request/wait/reply cycle. - TestPingItself pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, - transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, failOnce, - batchSize, queueCount); + TestPingItself pingItself = + new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, transacted, persistent, + messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, + queueCount, rate); pingItself.getConnection().start(); @@ -192,19 +181,29 @@ public class TestPingItself extends PingPongProducer pingThread.run(); pingThread.join(); } + pingItself.getConnection().close(); } private static void usage() { - System.err.println("Usage: TestPingPublisher \n" + - "-host : broker host" + - "-port : broker port" + - "-transacted : (true/false). Default is false" + - "-persistent : (true/false). Default is false" + - "-payload : paylaod size. Default is 0" + - "-queues : no of queues" + - "-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)"); + System.err.println("Usage: TestPingPublisher \n" + "-host : broker host" + "-port : broker port" + + "-transacted : (true/false). Default is false" + "-persistent : (true/false). Default is false" + + "-payload : paylaod size. Default is 0" + "-queues : no of queues" + + "-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)"); System.exit(0); } + + /** + * Sets the replyQueue to be the same as ping queue. + */ + @Override + public void createConsumer(String selector) throws JMSException + { + // Create a message consumer to get the replies with and register this to be called back by it. + setReplyQueue(getPingQueue()); + MessageConsumer consumer = + getConsumerSession().createConsumer(getReplyQueue(), PREFETCH, false, EXCLUSIVE, selector); + consumer.setMessageListener(this); + } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java index adf1c4dd9b..d9e81d39de 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java @@ -85,11 +85,10 @@ class TestPingProducer extends AbstractPingProducer */ private boolean _verbose = false; - public TestPingProducer(String brokerDetails, String username, String password, String virtualpath, String queueName, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, - boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, - int batchSize) throws Exception + boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize) + throws Exception { // Create a connection to the broker. InetAddress address = InetAddress.getLocalHost(); @@ -114,8 +113,7 @@ class TestPingProducer extends AbstractPingProducer _failBeforeCommit = beforeCommit; _failAfterSend = afterSend; _failBeforeSend = beforeSend; - _sentMessages = 0; - _batchSize = batchSize; + _txBatchSize = batchSize; _failOnce = failOnce; } @@ -131,8 +129,8 @@ class TestPingProducer extends AbstractPingProducer if (args.length < 2) { System.err.println( - "Usage: TestPingPublisher " + - "[ "); + "Usage: TestPingPublisher " + + "[ "); System.exit(0); } @@ -144,7 +142,6 @@ class TestPingProducer extends AbstractPingProducer int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; int batchSize = (args.length >= 7) ? Integer.parseInt(args[6]) : 1; - boolean afterCommit = false; boolean beforeCommit = false; boolean afterSend = false; @@ -170,6 +167,7 @@ class TestPingProducer extends AbstractPingProducer afterSend = parts[1].equals("after"); beforeSend = parts[1].equals("before"); } + if (parts[1].equals("once")) { failOnce = true; @@ -183,10 +181,9 @@ class TestPingProducer extends AbstractPingProducer } // Create a ping producer to generate the pings. - _pingProducer = new TestPingProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, - transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, failOnce, - batchSize); + _pingProducer = new TestPingProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, transacted, + persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, + beforeSend, failOnce, batchSize); // Start the connection running. _pingProducer.getConnection().start(); @@ -217,7 +214,7 @@ class TestPingProducer extends AbstractPingProducer String messageId = message.getJMSMessageID(); // Commit the transaction if running in transactional mode. This must happen now, rather than at the end of - // this method, as the message will not be sent until the transaction is committed. + // this method, as the message will not be sent until the transaction is committed. commitTx(); } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java index 9fb637149b..1e98e45bba 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java @@ -61,6 +61,7 @@ public class Throttle } // Keep the time of the last call to this method to calculate the next cycle. - lastTimeNanos = currentTimeNanos; + //lastTimeNanos = currentTimeNanos; + lastTimeNanos = System.nanoTime(); } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java index e7fe180d43..a7ad4b91b8 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -38,20 +38,14 @@ import org.apache.qpid.ping.AbstractPingClient; * ping messages generated by {@link org.apache.qpid.requestreply.PingPongProducer} but could be used for other purposes * too. * - *

    The message id from the received message is extracted, and placed into the reply as the correlation id. Messages - * are bounced back to the reply-to destination. The original sender of the message has the option to use either a unique + *

    The correlation id from the received message is extracted, and placed into the reply as the correlation id. Messages + * are bounced back to their reply-to destination. The original sender of the message has the option to use either a unique * temporary queue or the correlation id to correlate the original message to the reply. * *

    There is a verbose mode flag which causes information about each ping to be output to the console * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should * be disabled for real timing tests as writing to the console will slow things down. * - *

    When the a message is received, a reply to producer is created for it if it is not the same as the previous - * message. All subsequent replies are sent using that producer until a different reply to destination is - * encountered; effectively a last used cache of size 1. Fast because it saves creating the reply producer over and - * over again when the destination does not change. For a larger fixed set of reply to destinations could turn this - * into a cache with more elements. - * *

    *
    CRC Card
    Responsibilities Collaborations *
    Bounce back messages to their reply to destination. @@ -84,8 +78,8 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen /** Keeps track of the response destination of the previous message for the last reply to producer cache. */ private Destination _lastResponseDest; - /** The cached, most recently used reply producer. */ - private MessageProducer _cachedReplyProducer; + /** The producer for sending replies with. */ + private MessageProducer _replyProducer; /** The consumer session. */ private Session _consumerSession; @@ -96,16 +90,15 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen /** * Creates a PingPongBouncer on the specified producer and consumer sessions. * - * @param brokerDetails - * @param username - * @param password - * @param virtualpath - * @param queueName - * @param persistent - * @param transacted - * @param selector - * @param verbose - * @throws JMSException + * @param brokerDetails The addresses of the brokers to connect to. + * @param username The broker username. + * @param password The broker password. + * @param virtualpath The virtual host name within the broker. + * @param queueName The name of the queue to receive pings on (or root of the queue name where many queues are generated). + * @param persistent A flag to indicate that persistent message should be used. + * @param transacted A flag to indicate that pings should be sent within transactions. + * @param selector A message selector to filter received pings with. + * @param verbose A flag to indicate that message timings should be sent to the console. * * @throws Exception All underlying exceptions allowed to fall through. This is only test code... */ @@ -132,6 +125,11 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen Queue q = new AMQQueue(queueName); MessageConsumer consumer = _consumerSession.createConsumer(q, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); + // Create a producer for the replies, without a default destination. + _replyProducer = _producerSession.createProducer(null); + _replyProducer.setDisableMessageTimestamp(true); + _replyProducer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + _verbose = verbose; _persistent = persistent; @@ -199,23 +197,11 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen if (responseDest == null) { - _logger.debug("Producer not created because the response destination is null."); + _logger.debug("Cannot send reply because reply-to destination is null."); return; } - // Check if the reply to destination is different to the last message and create a new producer if so. - if (!responseDest.equals(_lastResponseDest)) - { - _lastResponseDest = responseDest; - - _logger.debug("About to create a producer."); - _cachedReplyProducer = _producerSession.createProducer(responseDest); - _cachedReplyProducer.setDisableMessageTimestamp(true); - _cachedReplyProducer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - _logger.debug("After create a producer."); - } - // Spew out some timing information if verbose mode is on. if (_verbose) { @@ -232,7 +218,7 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen message.setJMSCorrelationID(messageCorrelationId); // Send the receieved message as the pong reply. - _cachedReplyProducer.send(message); + _replyProducer.send(responseDest, message); if (_verbose) { diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 6ff0af214b..8d57174457 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -38,6 +38,7 @@ import org.apache.qpid.jms.ConnectionListener; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; import org.apache.qpid.ping.AbstractPingProducer; +import org.apache.qpid.ping.Throttle; /** * PingPongProducer is a client that sends pings to a queue and waits for pongs to be bounced back by a bounce back @@ -107,6 +108,11 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, */ private static AtomicLong idGenerator = new AtomicLong(0L); + /** + * Holds a map from message ids to latches on which threads wait for replies. + */ + private static Map trafficLights = new HashMap(); + /** * Holds the queue to send the ping replies to. */ @@ -127,11 +133,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, */ protected int _messageSize; - /** - * Holds a map from message ids to latches on which threads wait for replies. - */ - private static Map trafficLights = new HashMap(); - /** * Used to indicate that the ping loop should print out whenever it pings. */ @@ -139,11 +140,19 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, protected Session _consumerSession; - private PingPongProducer(String brokerDetails, String username, String password, String virtualpath, - boolean transacted, boolean persistent, int messageSize, boolean verbose, - boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, - int batchSize) - throws Exception + /** Used to restrict the sending rate to a specified limit. */ + private Throttle rateLimiter = null; + + /** + * The throttler can only reliably restrict to a few hundred cycles per second, so a throttling batch size is used + * to group sends together into batches large enough that the throttler runs slower than that. + */ + int _throttleBatchSize; + + private PingPongProducer(String brokerDetails, String username, String password, String virtualpath, boolean transacted, + boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, + boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, int rate) + throws Exception { // Create a connection to the broker. InetAddress address = InetAddress.getLocalHost(); @@ -165,8 +174,31 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _failAfterSend = afterSend; _failBeforeSend = beforeSend; _failOnce = failOnce; - _batchSize = batchSize; - _sentMessages = 0; + _txBatchSize = batchSize; + + // Calculate a throttling batch size and rate such that the throttle runs slower than 100 cycles per second + // and batched sends within each cycle multiply up to give the desired rate. + // + // total rate = throttle rate * batch size. + // 1 < throttle rate < 100 + // 1 < total rate < 20000 + if (rate > 0) + { + // Log base 10 over 2 is used here to get a feel for what power of 100 the total rate is. + // As the total rate goes up the powers of 100 the batch size goes up by powers of 100 to keep the + // throttle rate back into the range 1 to 100. + int x = (int) (Math.log10(rate) / 2); + _throttleBatchSize = (int) Math.pow(100, x); + int throttleRate = rate / _throttleBatchSize; + + _logger.info("rate = " + rate); + _logger.info("x = " + x); + _logger.info("_throttleBatchSize = " + _throttleBatchSize); + _logger.info("throttleRate = " + throttleRate); + + rateLimiter = new Throttle(); + rateLimiter.setRate(throttleRate); + } } /** @@ -181,12 +213,11 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, */ public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, String queueName, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, - boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, - int batchSize, int queueCount) - throws Exception + boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, + boolean failOnce, int batchSize, int queueCount, int rate) throws Exception { - this(brokerDetails, username, password, virtualpath, transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize); + this(brokerDetails, username, password, virtualpath, transacted, persistent, messageSize, verbose, afterCommit, + beforeCommit, afterSend, beforeSend, failOnce, batchSize, rate); _queueCount = queueCount; if (queueCount <= 1) @@ -206,76 +237,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } } - /** - * Creates the producer to send the pings on. If the tests are with nultiple queues, then producer - * is created with null destination, so that any destination can be specified while sending - * - * @throws JMSException - */ - public void createProducer() throws JMSException - { - if (getQueueCount() > 1) - { - // create producer with initial destination as null for test with multiple queues - // In this case, a different destination will be used while sending the message - _producer = (MessageProducer) getProducerSession().createProducer(null); - } - else - { - // Create a queue and producer to send the pings on. - _producer = (MessageProducer) getProducerSession().createProducer(_pingQueue); - - } - _producer.setDisableMessageTimestamp(true); - _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - } - - /** - * Creates the temporary queue to listen to the responses - * - * @param selector - * @throws JMSException - */ - public void createConsumer(String selector) throws JMSException - { - // Create a temporary queue to get the pongs on. - _replyQueue = _consumerSession.createTemporaryQueue(); - - // Create a message consumer to get the replies with and register this to be called back by it. - MessageConsumer consumer = _consumerSession.createConsumer(_replyQueue, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); - consumer.setMessageListener(this); - } - - /** - * Creates consumer instances for each queue. This is used when test is being done with multiple queues. - * - * @param selector - * @throws JMSException - */ - public void createConsumers(String selector) throws JMSException - { - for (int i = 0; i < getQueueCount(); i++) - { - MessageConsumer consumer = getConsumerSession().createConsumer(getQueue(i), PREFETCH, false, EXCLUSIVE, selector); - consumer.setMessageListener(this); - } - } - - protected Session getConsumerSession() - { - return _consumerSession; - } - - public Queue getPingQueue() - { - return _pingQueue; - } - - protected void setPingQueue(Queue queue) - { - _pingQueue = queue; - } - /** * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs * to be started to bounce the pings back again. @@ -295,8 +256,9 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Extract the command line. if (args.length < 2) { - System.err.println("Usage: TestPingPublisher [verbose (true/false)] " + - "[transacted (true/false)] [persistent (true/false)] [message size in bytes]"); + System.err.println( + "Usage: TestPingPublisher [verbose (true/false)] " + + "[transacted (true/false)] [persistent (true/false)] [message size in bytes] [batchsize] [rate]"); System.exit(0); } @@ -307,7 +269,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, boolean persistent = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; int batchSize = (args.length >= 7) ? Integer.parseInt(args[6]) : 1; - + int rate = (args.length >= 8) ? Integer.parseInt(args[7]) : 0; boolean afterCommit = false; boolean beforeCommit = false; @@ -334,6 +296,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, afterSend = parts[1].equals("after"); beforeSend = parts[1].equals("before"); } + if (parts[1].equals("once")) { failOnce = true; @@ -347,10 +310,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } // Create a ping producer to handle the request/wait/reply cycle. - PingPongProducer pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, null, transacted, - persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, failOnce, - batchSize, 0); + PingPongProducer pingProducer = + new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, null, transacted, persistent, + messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, + 0, rate); pingProducer.getConnection().start(); @@ -368,6 +331,68 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, pingThread.join(); } + /** + * Creates the producer to send the pings on. If the tests are with nultiple queues, then producer + * is created with null destination, so that any destination can be specified while sending + * + * @throws JMSException + */ + public void createProducer() throws JMSException + { + if (getQueueCount() > 1) + { + // create producer with initial destination as null for test with multiple queues + // In this case, a different destination will be used while sending the message + _producer = (MessageProducer) getProducerSession().createProducer(null); + } + else + { + // Create a queue and producer to send the pings on. + _producer = (MessageProducer) getProducerSession().createProducer(_pingQueue); + + } + + _producer.setDisableMessageTimestamp(true); + _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + } + + /** + * Creates the temporary queue to listen to the responses + * + * @param selector + * @throws JMSException + */ + public void createConsumer(String selector) throws JMSException + { + // Create a temporary queue to get the pongs on. + _replyQueue = _consumerSession.createTemporaryQueue(); + + // Create a message consumer to get the replies with and register this to be called back by it. + MessageConsumer consumer = _consumerSession.createConsumer(_replyQueue, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); + consumer.setMessageListener(this); + } + + /** + * Creates consumer instances for each queue. This is used when test is being done with multiple queues. + * + * @param selector + * @throws JMSException + */ + public void createConsumers(String selector) throws JMSException + { + for (int i = 0; i < getQueueCount(); i++) + { + MessageConsumer consumer = + getConsumerSession().createConsumer(getQueue(i), PREFETCH, false, EXCLUSIVE, selector); + consumer.setMessageListener(this); + } + } + + public Queue getPingQueue() + { + return _pingQueue; + } + /** * Primes the test loop by sending a few messages, then introduces a short wait. This allows the bounce back client * on the other end a chance to configure its reply producer on the reply to destination. It is also worth calling @@ -390,8 +415,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, Thread.sleep(100); } catch (InterruptedException ignore) - { - } + { } } } @@ -452,8 +476,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * @param message The message to send. * @param numPings The number of ping messages to send. * @param timeout The timeout in milliseconds. + * * @return The number of replies received. This may be less than the number sent if the timeout terminated the * wait for all prematurely. + * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ public int pingAndWaitForReply(Message message, int numPings, long timeout) throws JMSException, InterruptedException @@ -467,24 +493,52 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, CountDownLatch trafficLight = new CountDownLatch(numPings); trafficLights.put(messageCorrelationId, trafficLight); - if (getQueueCount() > 1) - { - // If test is with multiple queues - pingMultipleQueues(message, numPings); - } - else + // Set up a committed flag to detect uncommitted message at the end of the send loop. This may occurr if the + // transaction batch size is not a factor of the number of pings. In which case an extra commit at the end is + // needed. + boolean committed = false; + + // Send all of the ping messages. + for (int i = 0; i < numPings; i++) { - // If test is with one Queue only - for (int i = 0; i < numPings; i++) + // Reset the committed flag to indicate that there are uncommitted message. + committed = false; + + // Re-timestamp the message. + message.setLongProperty("timestamp", System.currentTimeMillis()); + + // Check if the test is with multiple queues, in which case round robin the queues as the messages are sent. + if (getQueueCount() > 1) + { + sendMessage(getQueue(i % getQueueCount()), message); + } + else { - // Re-timestamp the message. - message.setLongProperty("timestamp", System.currentTimeMillis()); sendMessage(message); } + + // Apply message rate throttling if a rate limit has been set up and the throttling batch limit has been + // reached. See the comment on the throttle batch size for information about the use of batches here. + if ((rateLimiter != null) && ((i % _throttleBatchSize) == 0)) + { + rateLimiter.throttle(); + } + + // Call commit every time the commit batch size is reached. + if ((i % _txBatchSize) == 0) + { + commitTx(); + committed = true; + } } - // Keep the messageId to correlate with the reply. - //String messageId = message.getJMSMessageID(); + // Call commit if the send loop finished before reaching a batch size boundary so there may still be uncommitted messages. + if (!committed) + { + commitTx(); + } + + // Spew out per message timings only in verbose mode. if (_verbose) { _logger.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); @@ -498,7 +552,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, if ((numReplies < numPings) && _verbose) { - _logger.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); + _logger.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); } else if (_verbose) { @@ -508,33 +562,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, return numReplies; } - /** - * When the test is being performed with multiple queues, then this method will be used, which has a loop to - * pick up the next queue from the queues list and sends message to it. - * - * @param message - * @param numPings - * @throws JMSException - */ - private void pingMultipleQueues(Message message, int numPings) throws JMSException - { - int queueIndex = 0; - for (int i = 0; i < numPings; i++) - { - // Re-timestamp the message. - message.setLongProperty("timestamp", System.currentTimeMillis()); - - sendMessage(getQueue(queueIndex++), message); - - // reset the counter to get the first queue - if (queueIndex == getQueueCount() - 1) - { - queueIndex = 0; - } - } - } - - /** + /* * Sends the specified ping message but does not wait for a correlating reply. * * @param message The message to send. @@ -542,7 +570,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * @return The reply, or null if no reply arrives before the timeout. * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ - public void pingNoWaitForReply(Message message, int numPings) throws JMSException, InterruptedException + /*public void pingNoWaitForReply(Message message, int numPings) throws JMSException, InterruptedException { for (int i = 0; i < numPings; i++) { @@ -553,7 +581,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _logger.info(timestampFormatter.format(new Date()) + ": Pinged at."); } } - } + }*/ /** * The ping loop implementation. This send out pings of the configured size, persistence and transactionality, and @@ -590,11 +618,47 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, return _replyQueue; } + protected Session getConsumerSession() + { + return _consumerSession; + } + + protected void setPingQueue(Queue queue) + { + _pingQueue = queue; + } + protected void setReplyQueue(Queue queue) { _replyQueue = queue; } + /* + * When the test is being performed with multiple queues, then this method will be used, which has a loop to + * pick up the next queue from the queues list and sends message to it. + * + * @param message + * @param numPings + * @throws JMSException + */ + /*private void pingMultipleQueues(Message message, int numPings) throws JMSException + { + int queueIndex = 0; + for (int i = 0; i < numPings; i++) + { + // Re-timestamp the message. + message.setLongProperty("timestamp", System.currentTimeMillis()); + + sendMessage(getQueue(queueIndex++), message); + + // reset the counter to get the first queue + if (queueIndex == (getQueueCount() - 1)) + { + queueIndex = 0; + } + } + }*/ + /** * A connection listener that logs out any failover complete events. Could do more interesting things with this * at some point... @@ -602,12 +666,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, public static class FailoverNotifier implements ConnectionListener { public void bytesSent(long count) - { - } + { } public void bytesReceived(long count) - { - } + { } public boolean preFailover(boolean redirect) { diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java index 439e1ee2ca..6af7929edc 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java @@ -47,6 +47,7 @@ public class Config extends AbstractConfig implements ConnectorConfig private boolean transacted; private int noOfQueues; private int batchSize; + private int rate; public Config() { @@ -92,6 +93,11 @@ public class Config extends AbstractConfig implements ConnectorConfig return batchSize; } + public int getRate() + { + return rate; + } + public int getQueueCount() { return noOfQueues; @@ -245,6 +251,10 @@ public class Config extends AbstractConfig implements ConnectorConfig { batchSize = parseInt("Bad batch size", value); } + else if ("-rate".equalsIgnoreCase(key)) + { + rate = parseInt("MEssage rate", value); + } else { System.out.println("Ignoring unrecognised option: " + key); -- cgit v1.2.1 From b6414eb4c6dc24ed3e7dc58b0d4a9f7e32bcaa61 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 23 Jan 2007 22:34:25 +0000 Subject: Updated perftests to include an Asynchronous ping sender git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499166 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/AbstractPingProducer.java | 1 + .../java/org/apache/qpid/ping/TestPingItself.java | 42 +++-- .../apache/qpid/requestreply/PingPongProducer.java | 170 +++++++++++---------- 3 files changed, 117 insertions(+), 96 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java index 33207790e7..34938a64bf 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java @@ -265,6 +265,7 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene _logger.trace("Batch time reached"); if (_failAfterSend) { + _logger.trace("Batch size reached"); if (_failOnce) { _failAfterSend = false; diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java index 35320d8b55..9a2e2c7e8c 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java @@ -20,6 +20,7 @@ package org.apache.qpid.ping; import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.ObjectMessage; +import javax.jms.MessageListener; import org.apache.log4j.Logger; @@ -41,6 +42,7 @@ public class TestPingItself extends PingPongProducer * If queueCount is > 1 : This creats a client for tests with multiple queues. Creates as many consumer instances * as there are queues, each listening to a Queue. A producer is created which picks up a queue from * the list of queues to send message + * * @param brokerDetails * @param username * @param password @@ -81,6 +83,25 @@ public class TestPingItself extends PingPongProducer } } + + /** + * Sets the replyQueue to be the same as ping queue. + */ + @Override + public void createConsumer(String selector) throws JMSException + { + // Create a message consumer to get the replies with and register this to be called back by it. + setReplyQueue(getPingQueue()); + MessageConsumer consumer = + getConsumerSession().createConsumer(getReplyQueue(), PREFETCH, false, EXCLUSIVE, selector); + consumer.setMessageListener(this); + } + + public void setMessageListener(MessageListener messageListener) throws JMSException + { + getConsumerSession().setMessageListener(messageListener); + } + /** * Starts a ping-pong loop running from the command line. * @@ -147,10 +168,10 @@ public class TestPingItself extends PingPongProducer } // Create a ping producer to handle the request/wait/reply cycle. - TestPingItself pingItself = - new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, transacted, persistent, - messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, - queueCount, rate); + TestPingItself pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, + transacted, persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, failOnce, + batchSize, queueCount, rate); pingItself.getConnection().start(); @@ -194,16 +215,5 @@ public class TestPingItself extends PingPongProducer System.exit(0); } - /** - * Sets the replyQueue to be the same as ping queue. - */ - @Override - public void createConsumer(String selector) throws JMSException - { - // Create a message consumer to get the replies with and register this to be called back by it. - setReplyQueue(getPingQueue()); - MessageConsumer consumer = - getConsumerSession().createConsumer(getReplyQueue(), PREFETCH, false, EXCLUSIVE, selector); - consumer.setMessageListener(this); - } + } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 8d57174457..e68c988d08 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -140,7 +140,9 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, protected Session _consumerSession; - /** Used to restrict the sending rate to a specified limit. */ + /** + * Used to restrict the sending rate to a specified limit. + */ private Throttle rateLimiter = null; /** @@ -152,7 +154,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, private PingPongProducer(String brokerDetails, String username, String password, String virtualpath, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, int rate) - throws Exception + throws Exception { // Create a connection to the broker. InetAddress address = InetAddress.getLocalHost(); @@ -237,6 +239,77 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } } + /** + * Creates the producer to send the pings on. If the tests are with nultiple queues, then producer + * is created with null destination, so that any destination can be specified while sending + * + * @throws JMSException + */ + public void createProducer() throws JMSException + { + if (getQueueCount() > 1) + { + // create producer with initial destination as null for test with multiple queues + // In this case, a different destination will be used while sending the message + _producer = (MessageProducer) getProducerSession().createProducer(null); + } + else + { + // Create a queue and producer to send the pings on. + _producer = (MessageProducer) getProducerSession().createProducer(_pingQueue); + + } + _producer.setDisableMessageTimestamp(true); + _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + } + + /** + * Creates the temporary queue to listen to the responses + * + * @param selector + * @throws JMSException + */ + public void createConsumer(String selector) throws JMSException + { + // Create a temporary queue to get the pongs on. + _replyQueue = _consumerSession.createTemporaryQueue(); + + // Create a message consumer to get the replies with and register this to be called back by it. + MessageConsumer consumer = _consumerSession.createConsumer(_replyQueue, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); + consumer.setMessageListener(this); + } + + /** + * Creates consumer instances for each queue. This is used when test is being done with multiple queues. + * + * @param selector + * @throws JMSException + */ + public void createConsumers(String selector) throws JMSException + { + for (int i = 0; i < getQueueCount(); i++) + { + MessageConsumer consumer = getConsumerSession().createConsumer(getQueue(i), PREFETCH, false, EXCLUSIVE, selector); + consumer.setMessageListener(this); + } + } + + + protected Session getConsumerSession() + { + return _consumerSession; + } + + public Queue getPingQueue() + { + return _pingQueue; + } + + protected void setPingQueue(Queue queue) + { + _pingQueue = queue; + } + /** * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs * to be started to bounce the pings back again. @@ -257,8 +330,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, if (args.length < 2) { System.err.println( - "Usage: TestPingPublisher [verbose (true/false)] " - + "[transacted (true/false)] [persistent (true/false)] [message size in bytes] [batchsize] [rate]"); + "Usage: TestPingPublisher [verbose (true/false)] " + + "[transacted (true/false)] [persistent (true/false)] [message size in bytes] [batchsize] [rate]"); System.exit(0); } @@ -310,10 +383,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } // Create a ping producer to handle the request/wait/reply cycle. - PingPongProducer pingProducer = - new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, null, transacted, persistent, - messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, - 0, rate); + PingPongProducer pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, null, transacted, + persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, failOnce, + batchSize, 0, rate); pingProducer.getConnection().start(); @@ -331,67 +404,12 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, pingThread.join(); } - /** - * Creates the producer to send the pings on. If the tests are with nultiple queues, then producer - * is created with null destination, so that any destination can be specified while sending - * - * @throws JMSException - */ - public void createProducer() throws JMSException - { - if (getQueueCount() > 1) - { - // create producer with initial destination as null for test with multiple queues - // In this case, a different destination will be used while sending the message - _producer = (MessageProducer) getProducerSession().createProducer(null); - } - else - { - // Create a queue and producer to send the pings on. - _producer = (MessageProducer) getProducerSession().createProducer(_pingQueue); - - } - - _producer.setDisableMessageTimestamp(true); - _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - } - - /** - * Creates the temporary queue to listen to the responses - * - * @param selector - * @throws JMSException - */ - public void createConsumer(String selector) throws JMSException - { - // Create a temporary queue to get the pongs on. - _replyQueue = _consumerSession.createTemporaryQueue(); - - // Create a message consumer to get the replies with and register this to be called back by it. - MessageConsumer consumer = _consumerSession.createConsumer(_replyQueue, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); - consumer.setMessageListener(this); - } - /** * Creates consumer instances for each queue. This is used when test is being done with multiple queues. * * @param selector * @throws JMSException */ - public void createConsumers(String selector) throws JMSException - { - for (int i = 0; i < getQueueCount(); i++) - { - MessageConsumer consumer = - getConsumerSession().createConsumer(getQueue(i), PREFETCH, false, EXCLUSIVE, selector); - consumer.setMessageListener(this); - } - } - - public Queue getPingQueue() - { - return _pingQueue; - } /** * Primes the test loop by sending a few messages, then introduces a short wait. This allows the bounce back client @@ -415,7 +433,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, Thread.sleep(100); } catch (InterruptedException ignore) - { } + { + } } } @@ -476,10 +495,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * @param message The message to send. * @param numPings The number of ping messages to send. * @param timeout The timeout in milliseconds. - * * @return The number of replies received. This may be less than the number sent if the timeout terminated the * wait for all prematurely. - * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ public int pingAndWaitForReply(Message message, int numPings, long timeout) throws JMSException, InterruptedException @@ -570,18 +587,18 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * @return The reply, or null if no reply arrives before the timeout. * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ - /*public void pingNoWaitForReply(Message message, int numPings) throws JMSException, InterruptedException + public void pingNoWaitForReply(Message message, int numPings) throws JMSException, InterruptedException { for (int i = 0; i < numPings; i++) { sendMessage(message); - + if (_verbose) { _logger.info(timestampFormatter.format(new Date()) + ": Pinged at."); } } - }*/ + } /** * The ping loop implementation. This send out pings of the configured size, persistence and transactionality, and @@ -618,15 +635,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, return _replyQueue; } - protected Session getConsumerSession() - { - return _consumerSession; - } - - protected void setPingQueue(Queue queue) - { - _pingQueue = queue; - } protected void setReplyQueue(Queue queue) { @@ -666,10 +674,12 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, public static class FailoverNotifier implements ConnectionListener { public void bytesSent(long count) - { } + { + } public void bytesReceived(long count) - { } + { + } public boolean preFailover(boolean redirect) { -- cgit v1.2.1 From 2b870f227b75ce2062895cf81a9c802746777c10 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Wed, 24 Jan 2007 11:05:35 +0000 Subject: updated the test classes to be used with Topics as well as Queues git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499356 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/message/TestMessageFactory.java | 37 +++++- .../org/apache/qpid/ping/AbstractPingClient.java | 12 ++ .../org/apache/qpid/ping/AbstractPingProducer.java | 112 +++++++++------- .../java/org/apache/qpid/ping/TestPingItself.java | 33 +++-- .../apache/qpid/requestreply/PingPongBouncer.java | 65 ++++++---- .../apache/qpid/requestreply/PingPongProducer.java | 141 ++++++++++++--------- .../main/java/org/apache/qpid/topic/Config.java | 10 ++ 7 files changed, 260 insertions(+), 150 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java index dc2bf39a9b..c0f236b833 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java @@ -26,6 +26,9 @@ import javax.jms.ObjectMessage; import javax.jms.StreamMessage; import javax.jms.BytesMessage; import javax.jms.TextMessage; +import javax.jms.Queue; +import javax.jms.DeliveryMode; +import javax.jms.Destination; public class TestMessageFactory { @@ -61,7 +64,39 @@ public class TestMessageFactory public static ObjectMessage newObjectMessage(Session session, int size) throws JMSException { - return session.createObjectMessage(createMessagePayload(size)); + if (size == 0) + { + return session.createObjectMessage(); + } + else + { + return session.createObjectMessage(createMessagePayload(size)); + } + } + + /** + * Creates an ObjectMessage with given size and sets the JMS properties (JMSReplyTo and DeliveryMode) + * @param session + * @param replyDestination + * @param size + * @param persistent + * @return the new ObjectMessage + * @throws JMSException + */ + public static ObjectMessage newObjectMessage(Session session, Destination replyDestination, int size, boolean persistent) throws JMSException + { + ObjectMessage msg = newObjectMessage(session, size); + + // Set the messages persistent delivery flag. + msg.setJMSDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + // Ensure that the temporary reply queue is set as the reply to destination for the message. + if (replyDestination != null) + { + msg.setJMSReplyTo(replyDestination); + } + + return msg; } public static String createMessagePayload(int size) diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java index c04a8a7d96..da40f73608 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java @@ -29,6 +29,8 @@ public abstract class AbstractPingClient private static final Logger _logger = Logger.getLogger(TestPingClient.class); private AMQConnection _connection; + /** tells if the test is being done for pubsub or p2p */ + private boolean _isPubSub = false; protected boolean _failBeforeCommit = false; protected boolean _failAfterCommit = false; @@ -43,6 +45,16 @@ public abstract class AbstractPingClient this._connection = _connection; } + public void setPubSub(boolean pubsub) + { + _isPubSub = pubsub; + } + + public boolean isPubSub() + { + return _isPubSub; + } + /** * Convenience method to commit the transaction on the session associated with this bounce back client. * diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java index 34938a64bf..1891c9b556 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java @@ -10,16 +10,14 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.jms.*; import javax.jms.Connection; import javax.jms.Message; -import javax.jms.MessageProducer; import org.apache.log4j.Logger; import org.apache.qpid.client.AMQNoConsumersException; import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.BasicMessageProducer; +import org.apache.qpid.client.AMQTopic; import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.jms.*; import org.apache.qpid.jms.Session; /** @@ -41,6 +39,8 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene { private static final Logger _logger = Logger.getLogger(AbstractPingProducer.class); + /** tells if the test is being done for pubsub or p2p */ + private boolean _isPubSub = false; /** * Used to format time stamping output. */ @@ -65,11 +65,12 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene private Session _producerSession; /** - * Holds the number of queues the tests will be using to send messages. By default it will be 1 + * Holds the number of destinations for multiple-destination test. By default it will be 1 */ - protected int _queueCount = 1; + protected int _destinationCount = 1; - private List _queues = new ArrayList(); + /** list of all the destinations for multiple-destinations test */ + private List _destinations = new ArrayList(); /** * Holds the message producer to send the pings through. @@ -85,6 +86,19 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene /** Holds the number of sends that should be performed in every transaction when using transactions. */ protected int _txBatchSize = 1; + /** + * Sets the test for pubsub or p2p. + * @param value + */ + public void setPubSub(boolean value) + { + _isPubSub = value; + } + + public boolean isPubSub() + { + return _isPubSub; + } /** * Convenience method for a short pause. * @@ -119,31 +133,11 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene * * @throws JMSException All underlying JMSException are allowed to fall through. */ - public ObjectMessage getTestMessage(Queue replyQueue, int messageSize, boolean persistent) throws JMSException + public ObjectMessage getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException { - ObjectMessage msg; - - if (messageSize != 0) - { - msg = TestMessageFactory.newObjectMessage(_producerSession, messageSize); - } - else - { - msg = _producerSession.createObjectMessage(); - } - - // Set the messages persistent delivery flag. - msg.setJMSDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - + ObjectMessage msg = TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); // Timestamp the message. msg.setLongProperty("timestamp", System.currentTimeMillis()); - - // Ensure that the temporary reply queue is set as the reply to destination for the message. - if (replyQueue != null) - { - msg.setJMSReplyTo(replyQueue); - } - return msg; } @@ -217,14 +211,14 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene this._producerSession = session; } - public int getQueueCount() + public int getDestinationsCount() { - return _queueCount; + return _destinationCount; } - public void setQueueCount(int queueCount) + public void setDestinationsCount(int count) { - this._queueCount = queueCount; + this._destinationCount = count; } protected void commitTx() throws JMSException @@ -233,31 +227,57 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene } /** - * Creates queues dynamically and adds to the queues list. This is when the test is being done with - * multiple queues. - * - * @param queueCount + * Creates destinations dynamically and adds to the destinations list for multiple-destinations test + * @param count */ - protected void createQueues(int queueCount) + protected void createDestinations(int count) + { + if (isPubSub()) + { + createTopics(count); + } + else + { + createQueues(count); + } + } + + private void createQueues(int count) { - for (int i = 0; i < queueCount; i++) + for (int i = 0; i < count; i++) { AMQShortString name = - new AMQShortString("Queue_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); + new AMQShortString("AMQQueue_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); AMQQueue queue = new AMQQueue(name, name, false, false, false); - _queues.add(queue); + _destinations.add(queue); } } - protected Queue getQueue(int index) + private void createTopics(int count) { - return _queues.get(index); + for (int i = 0; i < count; i++) + { + AMQShortString name = + new AMQShortString("AMQTopic_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); + AMQTopic topic = new AMQTopic(name); + + _destinations.add(topic); + } + } + + /** + * Returns the destination from the destinations list with given index. This is for multiple-destinations test + * @param index + * @return Destination with given index + */ + protected Destination getDestination(int index) + { + return _destinations.get(index); } /** * Convenience method to commit the transaction on the session associated with this pinger. - * * @throws javax.jms.JMSException If the commit fails and then the rollback fails. */ protected void commitTx(Session session) throws JMSException @@ -336,7 +356,7 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene sendMessage(null, message); } - protected void sendMessage(Queue q, Message message) throws JMSException + protected void sendMessage(Destination destination, Message message) throws JMSException { if (_failBeforeSend) { @@ -349,13 +369,13 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene doFailover(); } - if (q == null) + if (destination == null) { _producer.send(message); } else { - _producer.send(q, message); + _producer.send(destination, message); } commitTx(); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java index 9a2e2c7e8c..786aaa1e08 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java @@ -38,8 +38,8 @@ public class TestPingItself extends PingPongProducer private static final Logger _logger = Logger.getLogger(TestPingItself.class); /** - * If queueCount is <= 1 : There will be one Queue and one consumer instance for the test - * If queueCount is > 1 : This creats a client for tests with multiple queues. Creates as many consumer instances + * If noOfDestinations is <= 1 : There will be one Queue and one consumer instance for the test + * If noOfDestinations is > 1 : This creats a client for tests with multiple queues. Creates as many consumer instances * as there are queues, each listening to a Queue. A producer is created which picks up a queue from * the list of queues to send message * @@ -59,20 +59,21 @@ public class TestPingItself extends PingPongProducer * @param beforeSend * @param failOnce * @param batchSize - * @param queueCount + * @param noOfDestinations * @throws Exception */ public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String queueName, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, - int batchSize, int queueCount, int rate) throws Exception + int batchSize, int noOfDestinations, int rate, boolean pubsub) throws Exception { - super(brokerDetails, username, password, virtualpath, queueName, selector, transacted, persistent, messageSize, - verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, queueCount, rate); + super(brokerDetails, username, password, virtualpath, queueName, selector, transacted, persistent, + messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, + noOfDestinations, rate, pubsub); - if (queueCount > 1) + if (noOfDestinations > 1) { - createQueues(queueCount); + createDestinations(noOfDestinations); _persistent = persistent; _messageSize = messageSize; @@ -83,17 +84,16 @@ public class TestPingItself extends PingPongProducer } } - - /** + /** * Sets the replyQueue to be the same as ping queue. */ @Override public void createConsumer(String selector) throws JMSException { // Create a message consumer to get the replies with and register this to be called back by it. - setReplyQueue(getPingQueue()); + setReplyDestination(getPingDestination()); MessageConsumer consumer = - getConsumerSession().createConsumer(getReplyQueue(), PREFETCH, false, EXCLUSIVE, selector); + getConsumerSession().createConsumer(getReplyDestination(), PREFETCH, false, EXCLUSIVE, selector); consumer.setMessageListener(this); } @@ -123,6 +123,7 @@ public class TestPingItself extends PingPongProducer int queueCount = (config.getQueueCount() != 0) ? config.getQueueCount() : 1; int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : BATCH_SIZE; int rate = (config.getRate() != 0) ? config.getRate() : 0; + boolean pubsub = config.isPubSub(); String queue = "ping_" + System.currentTimeMillis(); _logger.info("Queue:" + queue + ", Transacted:" + transacted + ", persistent:" + persistent + ",MessageSize:" @@ -169,9 +170,9 @@ public class TestPingItself extends PingPongProducer // Create a ping producer to handle the request/wait/reply cycle. TestPingItself pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, - transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, failOnce, - batchSize, queueCount, rate); + transacted, persistent, messageSize, verbose, afterCommit, + beforeCommit, afterSend, beforeSend, failOnce, batchSize, + queueCount, rate, pubsub); pingItself.getConnection().start(); @@ -214,6 +215,4 @@ public class TestPingItself extends PingPongProducer + "-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)"); System.exit(0); } - - } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java index a7ad4b91b8..3b4572d1b3 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -29,6 +29,7 @@ import org.apache.log4j.Logger; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQTopic; import org.apache.qpid.jms.ConnectionListener; import org.apache.qpid.jms.Session; import org.apache.qpid.ping.AbstractPingClient; @@ -75,6 +76,8 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen /** Determines whether this bounce back client bounces back messages persistently. */ private boolean _persistent = false; + private Destination _consumerDestination; + /** Keeps track of the response destination of the previous message for the last reply to producer cache. */ private Destination _lastResponseDest; @@ -91,24 +94,28 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen * Creates a PingPongBouncer on the specified producer and consumer sessions. * * @param brokerDetails The addresses of the brokers to connect to. - * @param username The broker username. - * @param password The broker password. - * @param virtualpath The virtual host name within the broker. - * @param queueName The name of the queue to receive pings on (or root of the queue name where many queues are generated). - * @param persistent A flag to indicate that persistent message should be used. - * @param transacted A flag to indicate that pings should be sent within transactions. - * @param selector A message selector to filter received pings with. - * @param verbose A flag to indicate that message timings should be sent to the console. + * @param username The broker username. + * @param password The broker password. + * @param virtualpath The virtual host name within the broker. + * @param destinationName The name of the queue to receive pings on + * (or root of the queue name where many queues are generated). + * @param persistent A flag to indicate that persistent message should be used. + * @param transacted A flag to indicate that pings should be sent within transactions. + * @param selector A message selector to filter received pings with. + * @param verbose A flag to indicate that message timings should be sent to the console. * * @throws Exception All underlying exceptions allowed to fall through. This is only test code... */ - public PingPongBouncer(String brokerDetails, String username, String password, String virtualpath, String queueName, - boolean persistent, boolean transacted, String selector, boolean verbose) throws Exception + public PingPongBouncer(String brokerDetails, String username, String password, String virtualpath, + String destinationName, boolean persistent, boolean transacted, String selector, + boolean verbose, boolean pubsub) throws Exception { // Create a client id to uniquely identify this client. InetAddress address = InetAddress.getLocalHost(); String clientId = address.getHostName() + System.currentTimeMillis(); - + _verbose = verbose; + _persistent = persistent; + setPubSub(pubsub); // Connect to the broker. setConnection(new AMQConnection(brokerDetails, username, password, clientId, virtualpath)); _logger.info("Connected with URL:" + getConnection().toURL()); @@ -122,21 +129,30 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); // Create the queue to listen for message on. - Queue q = new AMQQueue(queueName); - MessageConsumer consumer = _consumerSession.createConsumer(q, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); + createConsumerDestination(destinationName); + MessageConsumer consumer = _consumerSession.createConsumer(_consumerDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); // Create a producer for the replies, without a default destination. _replyProducer = _producerSession.createProducer(null); _replyProducer.setDisableMessageTimestamp(true); _replyProducer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - _verbose = verbose; - _persistent = persistent; - // Set this up to listen for messages on the queue. consumer.setMessageListener(this); } + private void createConsumerDestination(String name) + { + if (isPubSub()) + { + _consumerDestination = new AMQTopic(name); + } + else + { + _consumerDestination = new AMQQueue(name); + } + } + /** * Starts a stand alone ping-pong client running in verbose mode. * @@ -149,8 +165,9 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen // Display help on the command line. if (args.length < 5) { - System.err.println("Usage: " - + "[ ] [selector]"); + System.err.println("Usage: " + + "[ ] " + + "[selector] [pubsub(true/false)]"); System.exit(1); } @@ -160,14 +177,15 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen String password = args[2]; String virtualpath = args[3]; String queueName = args[4]; - boolean persistent = ((args.length >= 6) && (args[5].toUpperCase().charAt(0) == 'P')); - boolean transacted = ((args.length >= 7) && (args[6].toUpperCase().charAt(0) == 'T')); - String selector = (args.length == 8) ? args[5] : null; + boolean persistent = ((args.length > 5) && (args[5].toUpperCase().charAt(0) == 'P')); + boolean transacted = ((args.length > 6) && (args[6].toUpperCase().charAt(0) == 'T')); + String selector = (args.length > 7) ? args[7] : null; + boolean pubsub = (args.length > 8) ? Boolean.parseBoolean(args[8]) : false; // Instantiate the ping pong client with the command line options and start it running. PingPongBouncer pingBouncer = - new PingPongBouncer(brokerDetails, username, password, virtualpath, queueName, persistent, transacted, selector, - true); + new PingPongBouncer(brokerDetails, username, password, virtualpath, queueName, persistent, transacted, + selector, true, pubsub); pingBouncer.getConnection().start(); System.out.println("Waiting..."); @@ -185,7 +203,6 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen try { String messageCorrelationId = message.getJMSCorrelationID(); - if (_verbose) { _logger.info(timestampFormatter.format(new Date()) + ": Got ping with correlation id, " diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index e68c988d08..2c27b48c88 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -34,6 +34,7 @@ import org.apache.log4j.Logger; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQTopic; import org.apache.qpid.jms.ConnectionListener; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; @@ -85,9 +86,9 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, protected static final long TIMEOUT = 9000; /** - * Holds the name of the queue to send pings on. + * Holds the name of the destination to send pings on. */ - protected static final String PING_QUEUE_NAME = "ping"; + protected static final String PING_DESTINATION_NAME = "ping"; /** * The batch size. @@ -114,14 +115,14 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, private static Map trafficLights = new HashMap(); /** - * Holds the queue to send the ping replies to. + * Destination where the responses messages will arrive */ - private Queue _replyQueue; + private Destination _replyDestination; /** - * Hold the known Queue where the producer will be sending message to + * Destination where the producer will be sending message to */ - private Queue _pingQueue; + private Destination _pingDestination; /** * Determines whether this producer sends persistent messages from the run method. @@ -213,20 +214,23 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * @param transacted * @throws Exception All allowed to fall through. This is only test code... */ - public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, String queueName, - String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, - boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, - boolean failOnce, int batchSize, int queueCount, int rate) throws Exception + public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, + String destinationName, String selector, boolean transacted, boolean persistent, + int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, + boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, + int noOfDestinations, int rate, boolean pubsub) throws Exception { this(brokerDetails, username, password, virtualpath, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, rate); - _queueCount = queueCount; - if (queueCount <= 1) + _destinationCount = noOfDestinations; + setPubSub(pubsub); + + if (noOfDestinations <= 1) { - if (queueName != null) + if (destinationName != null) { - _pingQueue = new AMQQueue(queueName); + createPingDestination(destinationName); // Create producer and the consumer createProducer(); createConsumer(selector); @@ -239,57 +243,76 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } } + private void createPingDestination(String name) + { + if (isPubSub()) + { + _pingDestination = new AMQTopic(name); + } + else + { + _pingDestination = new AMQQueue(name); + } + } + /** - * Creates the producer to send the pings on. If the tests are with nultiple queues, then producer + * Creates the producer to send the pings on. If the tests are with nultiple-destinations, then producer * is created with null destination, so that any destination can be specified while sending - * * @throws JMSException */ public void createProducer() throws JMSException { - if (getQueueCount() > 1) + if (getDestinationsCount() > 1) { - // create producer with initial destination as null for test with multiple queues + // create producer with initial destination as null for test with multiple-destinations // In this case, a different destination will be used while sending the message _producer = (MessageProducer) getProducerSession().createProducer(null); } else { - // Create a queue and producer to send the pings on. - _producer = (MessageProducer) getProducerSession().createProducer(_pingQueue); + // Create a producer with known destination to send the pings on. + _producer = (MessageProducer) getProducerSession().createProducer(_pingDestination); } + _producer.setDisableMessageTimestamp(true); _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); } /** - * Creates the temporary queue to listen to the responses - * + * Creates the temporary destination to listen to the responses * @param selector * @throws JMSException */ public void createConsumer(String selector) throws JMSException { - // Create a temporary queue to get the pongs on. - _replyQueue = _consumerSession.createTemporaryQueue(); + // Create a temporary destination to get the pongs on. + if (isPubSub()) + { + _replyDestination = _consumerSession.createTemporaryTopic(); + } + else + { + _replyDestination = _consumerSession.createTemporaryQueue(); + } // Create a message consumer to get the replies with and register this to be called back by it. - MessageConsumer consumer = _consumerSession.createConsumer(_replyQueue, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); + MessageConsumer consumer = _consumerSession.createConsumer(_replyDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); consumer.setMessageListener(this); } /** - * Creates consumer instances for each queue. This is used when test is being done with multiple queues. - * + * Creates consumer instances for each destination. This is used when test is being done with multiple destinations. + * * @param selector * @throws JMSException */ public void createConsumers(String selector) throws JMSException { - for (int i = 0; i < getQueueCount(); i++) + for (int i = 0; i < getDestinationsCount(); i++) { - MessageConsumer consumer = getConsumerSession().createConsumer(getQueue(i), PREFETCH, false, EXCLUSIVE, selector); + MessageConsumer consumer = + getConsumerSession().createConsumer(getDestination(i), PREFETCH, false, EXCLUSIVE, selector); consumer.setMessageListener(this); } } @@ -300,14 +323,14 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, return _consumerSession; } - public Queue getPingQueue() + public Destination getPingDestination() { - return _pingQueue; + return _pingDestination; } - protected void setPingQueue(Queue queue) + protected void setPingDestination(Destination destination) { - _pingQueue = queue; + _pingDestination = destination; } /** @@ -329,9 +352,9 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Extract the command line. if (args.length < 2) { - System.err.println( - "Usage: TestPingPublisher [verbose (true/false)] " - + "[transacted (true/false)] [persistent (true/false)] [message size in bytes] [batchsize] [rate]"); + System.err.println("Usage: TestPingPublisher [verbose (true/false)] " + + "[transacted (true/false)] [persistent (true/false)] [message size in bytes] [batchsize]" + + " [rate] [pubsub(true/false)]"); System.exit(0); } @@ -343,6 +366,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; int batchSize = (args.length >= 7) ? Integer.parseInt(args[6]) : 1; int rate = (args.length >= 8) ? Integer.parseInt(args[7]) : 0; + boolean ispubsub = (args.length >= 9) ? Boolean.parseBoolean(args[8]) : false; boolean afterCommit = false; boolean beforeCommit = false; @@ -383,34 +407,27 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } // Create a ping producer to handle the request/wait/reply cycle. - PingPongProducer pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, null, transacted, - persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, failOnce, - batchSize, 0, rate); + PingPongProducer pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, + PING_DESTINATION_NAME, null, transacted, persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, + 0, rate, ispubsub); pingProducer.getConnection().start(); // Run a few priming pings to remove warm up time from test results. - pingProducer.prime(PRIMING_LOOPS); + //pingProducer.prime(PRIMING_LOOPS); // Create a shutdown hook to terminate the ping-pong producer. Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. pingProducer.getConnection().setExceptionListener(pingProducer); - + // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. Thread pingThread = new Thread(pingProducer); pingThread.run(); pingThread.join(); } - /** - * Creates consumer instances for each queue. This is used when test is being done with multiple queues. - * - * @param selector - * @throws JMSException - */ - /** * Primes the test loop by sending a few messages, then introduces a short wait. This allows the bounce back client * on the other end a chance to configure its reply producer on the reply to destination. It is also worth calling @@ -424,8 +441,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, for (int i = 0; i < x; i++) { // Create and send a small message. - Message first = getTestMessage(_replyQueue, 0, false); - + Message first = getTestMessage(_replyDestination, 0, false); sendMessage(first); try @@ -434,6 +450,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } catch (InterruptedException ignore) { + } } } @@ -524,10 +541,11 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Re-timestamp the message. message.setLongProperty("timestamp", System.currentTimeMillis()); - // Check if the test is with multiple queues, in which case round robin the queues as the messages are sent. - if (getQueueCount() > 1) + // Check if the test is with multiple-destinations, in which case round robin the destinations + // as the messages are sent. + if (getDestinationsCount() > 1) { - sendMessage(getQueue(i % getQueueCount()), message); + sendMessage(getDestination(i % getDestinationsCount()), message); } else { @@ -609,7 +627,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, try { // Generate a sample message and time stamp it. - ObjectMessage msg = getTestMessage(_replyQueue, _messageSize, _persistent); + ObjectMessage msg = getTestMessage(_replyDestination, _messageSize, _persistent); msg.setLongProperty("timestamp", System.currentTimeMillis()); // Send the message and wait for a reply. @@ -630,15 +648,14 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } } - public Queue getReplyQueue() + public Destination getReplyDestination() { - return _replyQueue; + return _replyDestination; } - - protected void setReplyQueue(Queue queue) + protected void setReplyDestination(Destination destination) { - _replyQueue = queue; + _replyDestination = destination; } /* @@ -657,10 +674,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Re-timestamp the message. message.setLongProperty("timestamp", System.currentTimeMillis()); - sendMessage(getQueue(queueIndex++), message); + sendMessage(getDestination(queueIndex++), message); // reset the counter to get the first queue - if (queueIndex == (getQueueCount() - 1)) + if (queueIndex == (getDestinationsCount() - 1)) { queueIndex = 0; } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java index 6af7929edc..6ecb15155c 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java @@ -48,6 +48,7 @@ public class Config extends AbstractConfig implements ConnectorConfig private int noOfQueues; private int batchSize; private int rate; + private boolean ispubsub; public Config() { @@ -178,6 +179,11 @@ public class Config extends AbstractConfig implements ConnectorConfig return transacted; } + public boolean isPubSub() + { + return ispubsub; + } + public void setOption(String key, String value) { if("-host".equalsIgnoreCase(key)) @@ -255,6 +261,10 @@ public class Config extends AbstractConfig implements ConnectorConfig { rate = parseInt("MEssage rate", value); } + else if("-pubsub".equalsIgnoreCase(key)) + { + ispubsub = "true".equalsIgnoreCase(value); + } else { System.out.println("Ignoring unrecognised option: " + key); -- cgit v1.2.1 From ff91469bb8720637240d06e205f0a9da2e460073 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 24 Jan 2007 13:16:08 +0000 Subject: Updated Async Test for destinations and for signalling completed runs when there is only 1 queue. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499392 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/AbstractPingProducer.java | 4 +- .../java/org/apache/qpid/ping/TestPingItself.java | 10 +- .../apache/qpid/requestreply/PingPongBouncer.java | 2 +- .../apache/qpid/requestreply/PingPongProducer.java | 145 ++++++++++++--------- 4 files changed, 90 insertions(+), 71 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java index 1891c9b556..debaa0d785 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java @@ -376,9 +376,7 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene else { _producer.send(destination, message); - } - - commitTx(); + } } protected void doFailover(String broker) diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java index 786aaa1e08..72d8010fe3 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java @@ -26,6 +26,7 @@ import org.apache.log4j.Logger; import org.apache.qpid.requestreply.PingPongProducer; import org.apache.qpid.topic.Config; +import org.apache.qpid.util.concurrent.BooleanLatch; /** * This class is used to test sending and receiving messages to (pingQueue) and from a queue (replyQueue). @@ -71,7 +72,7 @@ public class TestPingItself extends PingPongProducer messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, noOfDestinations, rate, pubsub); - if (noOfDestinations > 1) + if (noOfDestinations > 0) { createDestinations(noOfDestinations); @@ -84,7 +85,7 @@ public class TestPingItself extends PingPongProducer } } - /** + /** * Sets the replyQueue to be the same as ping queue. */ @Override @@ -97,11 +98,6 @@ public class TestPingItself extends PingPongProducer consumer.setMessageListener(this); } - public void setMessageListener(MessageListener messageListener) throws JMSException - { - getConsumerSession().setMessageListener(messageListener); - } - /** * Starts a ping-pong loop running from the command line. * diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java index 3b4572d1b3..8a1583c609 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -172,7 +172,7 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen } // Extract all command line parameters. - String brokerDetails = args[0]; + String brokerDetails = args[0]; String username = args[1]; String password = args[2]; String virtualpath = args[3]; diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 2c27b48c88..2a8c7de5d7 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -152,6 +152,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, */ int _throttleBatchSize; + private MessageListener _messageListener = null; + private PingPongProducer(String brokerDetails, String username, String password, String virtualpath, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, int rate) @@ -225,8 +227,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _destinationCount = noOfDestinations; setPubSub(pubsub); - - if (noOfDestinations <= 1) + + if (noOfDestinations == 0) { if (destinationName != null) { @@ -237,8 +239,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } else { - _logger.error("Queue Name is not specified"); - throw new IllegalArgumentException("Queue Name is not specified"); + _logger.error("Destination is not specified"); + throw new IllegalArgumentException("Destination is not specified"); } } } @@ -258,6 +260,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, /** * Creates the producer to send the pings on. If the tests are with nultiple-destinations, then producer * is created with null destination, so that any destination can be specified while sending + * * @throws JMSException */ public void createProducer() throws JMSException @@ -281,6 +284,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, /** * Creates the temporary destination to listen to the responses + * * @param selector * @throws JMSException */ @@ -303,7 +307,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, /** * Creates consumer instances for each destination. This is used when test is being done with multiple destinations. - * + * * @param selector * @throws JMSException */ @@ -312,7 +316,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, for (int i = 0; i < getDestinationsCount(); i++) { MessageConsumer consumer = - getConsumerSession().createConsumer(getDestination(i), PREFETCH, false, EXCLUSIVE, selector); + getConsumerSession().createConsumer(getDestination(i), PREFETCH, false, EXCLUSIVE, selector); consumer.setMessageListener(this); } } @@ -353,8 +357,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, if (args.length < 2) { System.err.println("Usage: TestPingPublisher [verbose (true/false)] " + - "[transacted (true/false)] [persistent (true/false)] [message size in bytes] [batchsize]" + - " [rate] [pubsub(true/false)]"); + "[transacted (true/false)] [persistent (true/false)] [message size in bytes] [batchsize]" + + " [rate] [pubsub(true/false)]"); System.exit(0); } @@ -366,7 +370,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; int batchSize = (args.length >= 7) ? Integer.parseInt(args[6]) : 1; int rate = (args.length >= 8) ? Integer.parseInt(args[7]) : 0; - boolean ispubsub = (args.length >= 9) ? Boolean.parseBoolean(args[8]) : false; + boolean ispubsub = (args.length >= 9) ? Boolean.parseBoolean(args[8]) : false; boolean afterCommit = false; boolean beforeCommit = false; @@ -408,9 +412,9 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Create a ping producer to handle the request/wait/reply cycle. PingPongProducer pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, - PING_DESTINATION_NAME, null, transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, - 0, rate, ispubsub); + PING_DESTINATION_NAME, null, transacted, persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, + 0, rate, ispubsub); pingProducer.getConnection().start(); @@ -421,7 +425,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. pingProducer.getConnection().setExceptionListener(pingProducer); - + // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. Thread pingThread = new Thread(pingProducer); pingThread.run(); @@ -444,15 +448,19 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, Message first = getTestMessage(_replyDestination, 0, false); sendMessage(first); + commitTx(); + try { Thread.sleep(100); } catch (InterruptedException ignore) { - + } } + + } /** @@ -482,6 +490,12 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, { _logger.debug("Reply was expected, decrementing the latch for the id."); trafficLight.countDown(); + + if (_messageListener != null) + { + _messageListener.onMessage(message); + } + } else { @@ -519,14 +533,52 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, public int pingAndWaitForReply(Message message, int numPings, long timeout) throws JMSException, InterruptedException { // Put a unique correlation id on the message before sending it. - String messageCorrelationId = Long.toString(idGenerator.incrementAndGet()); - message.setJMSCorrelationID(messageCorrelationId); + String messageCorrelationId = Long.toString(getNewID()); + + + pingNoWaitForReply(message, numPings, messageCorrelationId); + + CountDownLatch trafficLight = trafficLights.get(messageCorrelationId); + // Block the current thread until a reply to the message is received, or it times out. + trafficLight.await(timeout, TimeUnit.MILLISECONDS); + + // Work out how many replies were receieved. + int numReplies = numPings - (int) trafficLight.getCount(); + + if ((numReplies < numPings) && _verbose) + { + _logger.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); + } + else if (_verbose) + { + _logger.info("Got all replies on id, " + messageCorrelationId); + } + return numReplies; + } + + public long getNewID() + { + return idGenerator.incrementAndGet(); + } + + /* + * Sends the specified ping message but does not wait for a correlating reply. + * + * @param message The message to send. + * @param numPings The number of pings to send. + * @return The reply, or null if no reply arrives before the timeout. + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + */ + public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException, InterruptedException + { // Create a count down latch to count the number of replies with. This is created before the message is sent // so that the message is not received before the count down is created. CountDownLatch trafficLight = new CountDownLatch(numPings); trafficLights.put(messageCorrelationId, trafficLight); + message.setJMSCorrelationID(messageCorrelationId); + // Set up a committed flag to detect uncommitted message at the end of the send loop. This may occurr if the // transaction batch size is not a factor of the number of pings. In which case an extra commit at the end is // needed. @@ -579,43 +631,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _logger.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); } - // Block the current thread until a reply to the message is received, or it times out. - trafficLight.await(timeout, TimeUnit.MILLISECONDS); - - // Work out how many replies were receieved. - int numReplies = numPings - (int) trafficLight.getCount(); - - if ((numReplies < numPings) && _verbose) - { - _logger.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); - } - else if (_verbose) - { - _logger.info("Got all replies on id, " + messageCorrelationId); - } - - return numReplies; - } - - /* - * Sends the specified ping message but does not wait for a correlating reply. - * - * @param message The message to send. - * @param numPings The number of pings to send. - * @return The reply, or null if no reply arrives before the timeout. - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - */ - public void pingNoWaitForReply(Message message, int numPings) throws JMSException, InterruptedException - { - for (int i = 0; i < numPings; i++) - { - sendMessage(message); - - if (_verbose) - { - _logger.info(timestampFormatter.format(new Date()) + ": Pinged at."); - } - } } /** @@ -658,14 +673,24 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _replyDestination = destination; } + public void setMessageListener(MessageListener messageListener) + { + _messageListener = messageListener; + } + + public CountDownLatch getEndLock(String correlationID) + { + return trafficLights.get(correlationID); + } + /* - * When the test is being performed with multiple queues, then this method will be used, which has a loop to - * pick up the next queue from the queues list and sends message to it. - * - * @param message - * @param numPings - * @throws JMSException - */ + * When the test is being performed with multiple queues, then this method will be used, which has a loop to + * pick up the next queue from the queues list and sends message to it. + * + * @param message + * @param numPings + * @throws JMSException + */ /*private void pingMultipleQueues(Message message, int numPings) throws JMSException { int queueIndex = 0; -- cgit v1.2.1 From 1dca68149b28d427d82867817eba50ffed02b04c Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Wed, 24 Jan 2007 15:02:07 +0000 Subject: git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499426 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/ping/TestPingItself.java | 48 ++++++++++++++------ .../apache/qpid/requestreply/PingPongBouncer.java | 52 +++++++++++++++------- .../main/java/org/apache/qpid/topic/Config.java | 30 ++++++++++--- 3 files changed, 95 insertions(+), 35 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java index 72d8010fe3..e7515b0f78 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java @@ -75,7 +75,6 @@ public class TestPingItself extends PingPongProducer if (noOfDestinations > 0) { createDestinations(noOfDestinations); - _persistent = persistent; _messageSize = messageSize; _verbose = verbose; @@ -108,22 +107,38 @@ public class TestPingItself extends PingPongProducer // Extract the command line. Config config = new Config(); config.setOptions(args); + if (args.length == 0) + { + _logger.info("Running test with default values..."); + } String brokerDetails = config.getHost() + ":" + config.getPort(); String virtualpath = "/test"; - boolean verbose = false; + boolean verbose = true; boolean transacted = config.isTransacted(); boolean persistent = config.usePersistentMessages(); int messageSize = (config.getPayload() != 0) ? config.getPayload() : DEFAULT_MESSAGE_SIZE; int messageCount = config.getMessages(); - int queueCount = (config.getQueueCount() != 0) ? config.getQueueCount() : 1; + int destCount = (config.getDestinationsCount() != 0) ? config.getDestinationsCount() : 1; int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : BATCH_SIZE; int rate = (config.getRate() != 0) ? config.getRate() : 0; boolean pubsub = config.isPubSub(); - String queue = "ping_" + System.currentTimeMillis(); - _logger.info("Queue:" + queue + ", Transacted:" + transacted + ", persistent:" + persistent + ",MessageSize:" - + messageSize + " bytes"); + String destName = config.getDestination(); + if (destName == null) + { + destName = PING_DESTINATION_NAME; + } + if (destCount > 1) + { + _logger.info("Destination Count:" + destCount + ", Transacted:" + transacted + ", persistent:" + + persistent + ",Message Size:" + messageSize + " bytes, pubsub:" + pubsub); + } + else + { + _logger.info("Destination:" + destName + ", Transacted:" + transacted + ", persistent:" + + persistent + ",Message Size:" + messageSize + " bytes, pubsub:" + pubsub); + } boolean afterCommit = false; boolean beforeCommit = false; @@ -165,10 +180,10 @@ public class TestPingItself extends PingPongProducer } // Create a ping producer to handle the request/wait/reply cycle. - TestPingItself pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, queue, null, + TestPingItself pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, destName, null, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, - queueCount, rate, pubsub); + destCount, rate, pubsub); pingItself.getConnection().start(); @@ -178,7 +193,7 @@ public class TestPingItself extends PingPongProducer // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. pingItself.getConnection().setExceptionListener(pingItself); - if ((queueCount > 1) || (messageCount > 0)) + if ((destCount > 1) || (messageCount > 0)) { ObjectMessage msg = pingItself.getTestMessage(null, messageSize, persistent); @@ -205,10 +220,17 @@ public class TestPingItself extends PingPongProducer private static void usage() { - System.err.println("Usage: TestPingPublisher \n" + "-host : broker host" + "-port : broker port" - + "-transacted : (true/false). Default is false" + "-persistent : (true/false). Default is false" - + "-payload : paylaod size. Default is 0" + "-queues : no of queues" - + "-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)"); + System.err.println("Usage: TestPingPublisher \n" + "-host : broker host" + "-port : broker port" + + "-destinationname : queue/topic name\n" + + "-transacted : (true/false). Default is false\n" + + "-persistent : (true/false). Default is false\n" + + "-pubsub : (true/false). Default is false\n" + + "-selector : selector string\n" + + "-payload : paylaod size. Default is 0\n" + + "-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)\n" + + "-destinationscount : no of destinations for multi-destinations test\n" + + "-batchsize : batch size\n" + + "-rate : thruput rate\n"); System.exit(0); } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java index 8a1583c609..bae6aa0dc2 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -33,6 +33,7 @@ import org.apache.qpid.client.AMQTopic; import org.apache.qpid.jms.ConnectionListener; import org.apache.qpid.jms.Session; import org.apache.qpid.ping.AbstractPingClient; +import org.apache.qpid.topic.Config; /** * PingPongBouncer is a message listener the bounces back messages to their reply to destination. This is used to return @@ -67,6 +68,8 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen /** The default no local flag for the message consumer. */ private static final boolean NO_LOCAL = true; + private static final String DEFAULT_DESTINATION_NAME = "ping"; + /** The default exclusive flag for the message consumer. */ private static final boolean EXCLUSIVE = false; @@ -163,29 +166,34 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen System.out.println("Starting..."); // Display help on the command line. - if (args.length < 5) + if (args.length == 0) { - System.err.println("Usage: " + - "[ ] " + - "[selector] [pubsub(true/false)]"); - System.exit(1); + _logger.info("Running test with default values..."); + //usage(); + //System.exit(0); } // Extract all command line parameters. - String brokerDetails = args[0]; - String username = args[1]; - String password = args[2]; - String virtualpath = args[3]; - String queueName = args[4]; - boolean persistent = ((args.length > 5) && (args[5].toUpperCase().charAt(0) == 'P')); - boolean transacted = ((args.length > 6) && (args[6].toUpperCase().charAt(0) == 'T')); - String selector = (args.length > 7) ? args[7] : null; - boolean pubsub = (args.length > 8) ? Boolean.parseBoolean(args[8]) : false; + Config config = new Config(); + config.setOptions(args); + String brokerDetails = config.getHost() + ":" + config.getPort(); + String virtualpath = "/test"; + String destinationName = config.getDestination(); + if (destinationName == null) + { + destinationName = DEFAULT_DESTINATION_NAME; + } + String selector = config.getSelector(); + boolean transacted = config.isTransacted(); + boolean persistent = config.usePersistentMessages(); + boolean pubsub = config.isPubSub(); + boolean verbose = true; + + //String selector = null; // Instantiate the ping pong client with the command line options and start it running. - PingPongBouncer pingBouncer = - new PingPongBouncer(brokerDetails, username, password, virtualpath, queueName, persistent, transacted, - selector, true, pubsub); + PingPongBouncer pingBouncer = new PingPongBouncer(brokerDetails, "guest", "guest", virtualpath, + destinationName, persistent, transacted, selector, verbose, pubsub); pingBouncer.getConnection().start(); System.out.println("Waiting..."); @@ -252,6 +260,16 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen } } + private static void usage() + { + System.err.println("Usage: PingPongBouncer \n" + "-host : broker host\n" + "-port : broker port\n" + + "-destinationname : queue/topic name\n" + + "-transacted : (true/false). Default is false\n" + + "-persistent : (true/false). Default is false\n" + + "-pubsub : (true/false). Default is false\n" + + "-selector : selector string\n"); + } + /** * A connection listener that logs out any failover complete events. Could do more interesting things with this * at some point... diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java index 6ecb15155c..60aa9f3930 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java @@ -43,9 +43,11 @@ public class Config extends AbstractConfig implements ConnectorConfig private int ackMode= AMQSession.NO_ACKNOWLEDGE; private String clientId; private String subscriptionId; + private String selector; + private String destinationName; private boolean persistent; private boolean transacted; - private int noOfQueues; + private int destinationsCount; private int batchSize; private int rate; private boolean ispubsub; @@ -99,9 +101,9 @@ public class Config extends AbstractConfig implements ConnectorConfig return rate; } - public int getQueueCount() + public int getDestinationsCount() { - return noOfQueues; + return destinationsCount; } public String getHost() @@ -169,6 +171,16 @@ public class Config extends AbstractConfig implements ConnectorConfig return subscriptionId; } + public String getSelector() + { + return selector; + } + + public String getDestination() + { + return destinationName; + } + public boolean usePersistentMessages() { return persistent; @@ -249,9 +261,9 @@ public class Config extends AbstractConfig implements ConnectorConfig { transacted = "true".equalsIgnoreCase(value); } - else if ("-queues".equalsIgnoreCase(key)) + else if ("-destinationscount".equalsIgnoreCase(key)) { - noOfQueues = parseInt("Bad queues count", value); + destinationsCount = parseInt("Bad destinations count", value); } else if ("-batchsize".equalsIgnoreCase(key)) { @@ -265,6 +277,14 @@ public class Config extends AbstractConfig implements ConnectorConfig { ispubsub = "true".equalsIgnoreCase(value); } + else if("-selector".equalsIgnoreCase(key)) + { + selector = value; + } + else if("-destinationname".equalsIgnoreCase(key)) + { + destinationName = value; + } else { System.out.println("Ignoring unrecognised option: " + key); -- cgit v1.2.1 From b858240d8cf3c9e0c23910ef85e9acdb7af95684 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 24 Jan 2007 15:04:06 +0000 Subject: (Patch submitted by Rupert Smith) Cleans up the countdown latch used to count expected number of messages. Not clearing it from the map of countdowns by message correlation id causes a memory leak as the map is long lived over many tests. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499427 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongProducer.java | 237 ++++++++++----------- 1 file changed, 118 insertions(+), 119 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 2a8c7de5d7..fa0887b3c9 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -157,7 +157,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, private PingPongProducer(String brokerDetails, String username, String password, String virtualpath, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, int rate) - throws Exception + throws Exception { // Create a connection to the broker. InetAddress address = InetAddress.getLocalHost(); @@ -217,10 +217,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * @throws Exception All allowed to fall through. This is only test code... */ public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, - String destinationName, String selector, boolean transacted, boolean persistent, - int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, - boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, - int noOfDestinations, int rate, boolean pubsub) throws Exception + String destinationName, String selector, boolean transacted, boolean persistent, int messageSize, + boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, + boolean beforeSend, boolean failOnce, int batchSize, int noOfDestinations, int rate, + boolean pubsub) throws Exception { this(brokerDetails, username, password, virtualpath, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, rate); @@ -245,98 +245,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } } - private void createPingDestination(String name) - { - if (isPubSub()) - { - _pingDestination = new AMQTopic(name); - } - else - { - _pingDestination = new AMQQueue(name); - } - } - - /** - * Creates the producer to send the pings on. If the tests are with nultiple-destinations, then producer - * is created with null destination, so that any destination can be specified while sending - * - * @throws JMSException - */ - public void createProducer() throws JMSException - { - if (getDestinationsCount() > 1) - { - // create producer with initial destination as null for test with multiple-destinations - // In this case, a different destination will be used while sending the message - _producer = (MessageProducer) getProducerSession().createProducer(null); - } - else - { - // Create a producer with known destination to send the pings on. - _producer = (MessageProducer) getProducerSession().createProducer(_pingDestination); - - } - - _producer.setDisableMessageTimestamp(true); - _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - } - - /** - * Creates the temporary destination to listen to the responses - * - * @param selector - * @throws JMSException - */ - public void createConsumer(String selector) throws JMSException - { - // Create a temporary destination to get the pongs on. - if (isPubSub()) - { - _replyDestination = _consumerSession.createTemporaryTopic(); - } - else - { - _replyDestination = _consumerSession.createTemporaryQueue(); - } - - // Create a message consumer to get the replies with and register this to be called back by it. - MessageConsumer consumer = _consumerSession.createConsumer(_replyDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); - consumer.setMessageListener(this); - } - - /** - * Creates consumer instances for each destination. This is used when test is being done with multiple destinations. - * - * @param selector - * @throws JMSException - */ - public void createConsumers(String selector) throws JMSException - { - for (int i = 0; i < getDestinationsCount(); i++) - { - MessageConsumer consumer = - getConsumerSession().createConsumer(getDestination(i), PREFETCH, false, EXCLUSIVE, selector); - consumer.setMessageListener(this); - } - } - - - protected Session getConsumerSession() - { - return _consumerSession; - } - - public Destination getPingDestination() - { - return _pingDestination; - } - - protected void setPingDestination(Destination destination) - { - _pingDestination = destination; - } - /** * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs * to be started to bounce the pings back again. @@ -356,9 +264,9 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Extract the command line. if (args.length < 2) { - System.err.println("Usage: TestPingPublisher [verbose (true/false)] " + - "[transacted (true/false)] [persistent (true/false)] [message size in bytes] [batchsize]" + - " [rate] [pubsub(true/false)]"); + System.err.println("Usage: TestPingPublisher [verbose (true/false)] " + + "[transacted (true/false)] [persistent (true/false)] [message size in bytes] [batchsize]" + + " [rate] [pubsub(true/false)]"); System.exit(0); } @@ -411,10 +319,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } // Create a ping producer to handle the request/wait/reply cycle. - PingPongProducer pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, - PING_DESTINATION_NAME, null, transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, - 0, rate, ispubsub); + PingPongProducer pingProducer = + new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, PING_DESTINATION_NAME, null, transacted, + persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, + failOnce, batchSize, 0, rate, ispubsub); pingProducer.getConnection().start(); @@ -432,6 +340,76 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, pingThread.join(); } + /** + * Creates the producer to send the pings on. If the tests are with nultiple-destinations, then producer + * is created with null destination, so that any destination can be specified while sending + * + * @throws JMSException + */ + public void createProducer() throws JMSException + { + if (getDestinationsCount() > 1) + { + // create producer with initial destination as null for test with multiple-destinations + // In this case, a different destination will be used while sending the message + _producer = (MessageProducer) getProducerSession().createProducer(null); + } + else + { + // Create a producer with known destination to send the pings on. + _producer = (MessageProducer) getProducerSession().createProducer(_pingDestination); + + } + + _producer.setDisableMessageTimestamp(true); + _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + } + + /** + * Creates the temporary destination to listen to the responses + * + * @param selector + * @throws JMSException + */ + public void createConsumer(String selector) throws JMSException + { + // Create a temporary destination to get the pongs on. + if (isPubSub()) + { + _replyDestination = _consumerSession.createTemporaryTopic(); + } + else + { + _replyDestination = _consumerSession.createTemporaryQueue(); + } + + // Create a message consumer to get the replies with and register this to be called back by it. + MessageConsumer consumer = + _consumerSession.createConsumer(_replyDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); + consumer.setMessageListener(this); + } + + /** + * Creates consumer instances for each destination. This is used when test is being done with multiple destinations. + * + * @param selector + * @throws JMSException + */ + public void createConsumers(String selector) throws JMSException + { + for (int i = 0; i < getDestinationsCount(); i++) + { + MessageConsumer consumer = + getConsumerSession().createConsumer(getDestination(i), PREFETCH, false, EXCLUSIVE, selector); + consumer.setMessageListener(this); + } + } + + public Destination getPingDestination() + { + return _pingDestination; + } + /** * Primes the test loop by sending a few messages, then introduces a short wait. This allows the bounce back client * on the other end a chance to configure its reply producer on the reply to destination. It is also worth calling @@ -455,12 +433,9 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, Thread.sleep(100); } catch (InterruptedException ignore) - { - - } + { } } - } /** @@ -535,13 +510,16 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Put a unique correlation id on the message before sending it. String messageCorrelationId = Long.toString(getNewID()); - pingNoWaitForReply(message, numPings, messageCorrelationId); CountDownLatch trafficLight = trafficLights.get(messageCorrelationId); + // Block the current thread until a reply to the message is received, or it times out. trafficLight.await(timeout, TimeUnit.MILLISECONDS); + // Remove the countdown latch from the map because the map is long lived, so will cause a memory leak. + trafficLights.remove(messageCorrelationId); + // Work out how many replies were receieved. int numReplies = numPings - (int) trafficLight.getCount(); @@ -570,7 +548,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * @return The reply, or null if no reply arrives before the timeout. * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ - public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException, InterruptedException + public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) + throws JMSException, InterruptedException { // Create a count down latch to count the number of replies with. This is created before the message is sent // so that the message is not received before the count down is created. @@ -668,11 +647,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, return _replyDestination; } - protected void setReplyDestination(Destination destination) - { - _replyDestination = destination; - } - public void setMessageListener(MessageListener messageListener) { _messageListener = messageListener; @@ -683,6 +657,33 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, return trafficLights.get(correlationID); } + protected Session getConsumerSession() + { + return _consumerSession; + } + + protected void setPingDestination(Destination destination) + { + _pingDestination = destination; + } + + protected void setReplyDestination(Destination destination) + { + _replyDestination = destination; + } + + private void createPingDestination(String name) + { + if (isPubSub()) + { + _pingDestination = new AMQTopic(name); + } + else + { + _pingDestination = new AMQQueue(name); + } + } + /* * When the test is being performed with multiple queues, then this method will be used, which has a loop to * pick up the next queue from the queues list and sends message to it. @@ -716,12 +717,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, public static class FailoverNotifier implements ConnectionListener { public void bytesSent(long count) - { - } + { } public void bytesReceived(long count) - { - } + { } public boolean preFailover(boolean redirect) { -- cgit v1.2.1 From e99bbab21e8364967d325e451d4ebea8be33f955 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 24 Jan 2007 15:08:13 +0000 Subject: Added commit calls for the received messages. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499429 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongProducer.java | 249 +++++++++++---------- 1 file changed, 130 insertions(+), 119 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index fa0887b3c9..da63a6ae96 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -157,7 +157,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, private PingPongProducer(String brokerDetails, String username, String password, String virtualpath, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, int rate) - throws Exception + throws Exception { // Create a connection to the broker. InetAddress address = InetAddress.getLocalHost(); @@ -217,10 +217,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * @throws Exception All allowed to fall through. This is only test code... */ public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, - String destinationName, String selector, boolean transacted, boolean persistent, int messageSize, - boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, - boolean beforeSend, boolean failOnce, int batchSize, int noOfDestinations, int rate, - boolean pubsub) throws Exception + String destinationName, String selector, boolean transacted, boolean persistent, + int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, + boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, + int noOfDestinations, int rate, boolean pubsub) throws Exception { this(brokerDetails, username, password, virtualpath, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, rate); @@ -245,6 +245,98 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } } + private void createPingDestination(String name) + { + if (isPubSub()) + { + _pingDestination = new AMQTopic(name); + } + else + { + _pingDestination = new AMQQueue(name); + } + } + + /** + * Creates the producer to send the pings on. If the tests are with nultiple-destinations, then producer + * is created with null destination, so that any destination can be specified while sending + * + * @throws JMSException + */ + public void createProducer() throws JMSException + { + if (getDestinationsCount() > 1) + { + // create producer with initial destination as null for test with multiple-destinations + // In this case, a different destination will be used while sending the message + _producer = (MessageProducer) getProducerSession().createProducer(null); + } + else + { + // Create a producer with known destination to send the pings on. + _producer = (MessageProducer) getProducerSession().createProducer(_pingDestination); + + } + + _producer.setDisableMessageTimestamp(true); + _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + } + + /** + * Creates the temporary destination to listen to the responses + * + * @param selector + * @throws JMSException + */ + public void createConsumer(String selector) throws JMSException + { + // Create a temporary destination to get the pongs on. + if (isPubSub()) + { + _replyDestination = _consumerSession.createTemporaryTopic(); + } + else + { + _replyDestination = _consumerSession.createTemporaryQueue(); + } + + // Create a message consumer to get the replies with and register this to be called back by it. + MessageConsumer consumer = _consumerSession.createConsumer(_replyDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); + consumer.setMessageListener(this); + } + + /** + * Creates consumer instances for each destination. This is used when test is being done with multiple destinations. + * + * @param selector + * @throws JMSException + */ + public void createConsumers(String selector) throws JMSException + { + for (int i = 0; i < getDestinationsCount(); i++) + { + MessageConsumer consumer = + getConsumerSession().createConsumer(getDestination(i), PREFETCH, false, EXCLUSIVE, selector); + consumer.setMessageListener(this); + } + } + + + public Session getConsumerSession() + { + return _consumerSession; + } + + public Destination getPingDestination() + { + return _pingDestination; + } + + protected void setPingDestination(Destination destination) + { + _pingDestination = destination; + } + /** * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs * to be started to bounce the pings back again. @@ -264,9 +356,9 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Extract the command line. if (args.length < 2) { - System.err.println("Usage: TestPingPublisher [verbose (true/false)] " - + "[transacted (true/false)] [persistent (true/false)] [message size in bytes] [batchsize]" - + " [rate] [pubsub(true/false)]"); + System.err.println("Usage: TestPingPublisher [verbose (true/false)] " + + "[transacted (true/false)] [persistent (true/false)] [message size in bytes] [batchsize]" + + " [rate] [pubsub(true/false)]"); System.exit(0); } @@ -319,10 +411,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } // Create a ping producer to handle the request/wait/reply cycle. - PingPongProducer pingProducer = - new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, PING_DESTINATION_NAME, null, transacted, - persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, - failOnce, batchSize, 0, rate, ispubsub); + PingPongProducer pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, + PING_DESTINATION_NAME, null, transacted, persistent, messageSize, verbose, + afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, + 0, rate, ispubsub); pingProducer.getConnection().start(); @@ -340,76 +432,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, pingThread.join(); } - /** - * Creates the producer to send the pings on. If the tests are with nultiple-destinations, then producer - * is created with null destination, so that any destination can be specified while sending - * - * @throws JMSException - */ - public void createProducer() throws JMSException - { - if (getDestinationsCount() > 1) - { - // create producer with initial destination as null for test with multiple-destinations - // In this case, a different destination will be used while sending the message - _producer = (MessageProducer) getProducerSession().createProducer(null); - } - else - { - // Create a producer with known destination to send the pings on. - _producer = (MessageProducer) getProducerSession().createProducer(_pingDestination); - - } - - _producer.setDisableMessageTimestamp(true); - _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - } - - /** - * Creates the temporary destination to listen to the responses - * - * @param selector - * @throws JMSException - */ - public void createConsumer(String selector) throws JMSException - { - // Create a temporary destination to get the pongs on. - if (isPubSub()) - { - _replyDestination = _consumerSession.createTemporaryTopic(); - } - else - { - _replyDestination = _consumerSession.createTemporaryQueue(); - } - - // Create a message consumer to get the replies with and register this to be called back by it. - MessageConsumer consumer = - _consumerSession.createConsumer(_replyDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); - consumer.setMessageListener(this); - } - - /** - * Creates consumer instances for each destination. This is used when test is being done with multiple destinations. - * - * @param selector - * @throws JMSException - */ - public void createConsumers(String selector) throws JMSException - { - for (int i = 0; i < getDestinationsCount(); i++) - { - MessageConsumer consumer = - getConsumerSession().createConsumer(getDestination(i), PREFETCH, false, EXCLUSIVE, selector); - consumer.setMessageListener(this); - } - } - - public Destination getPingDestination() - { - return _pingDestination; - } - /** * Primes the test loop by sending a few messages, then introduces a short wait. This allows the bounce back client * on the other end a chance to configure its reply producer on the reply to destination. It is also worth calling @@ -433,9 +455,12 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, Thread.sleep(100); } catch (InterruptedException ignore) - { } + { + + } } + } /** @@ -463,9 +488,16 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, if (trafficLight != null) { - _logger.debug("Reply was expected, decrementing the latch for the id."); + _logger.trace("Reply was expected, decrementing the latch for the id."); trafficLight.countDown(); + long remainingCount = trafficLight.getCount(); + + if ((remainingCount % _txBatchSize) == 0) + { + commitTx(getConsumerSession()); + } + if (_messageListener != null) { _messageListener.onMessage(message); @@ -474,7 +506,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } else { - _logger.debug("There was no thread waiting for reply: " + correlationID); + _logger.trace("There was no thread waiting for reply: " + correlationID); } if (_verbose) @@ -484,7 +516,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, if (timestamp != null) { long diff = System.currentTimeMillis() - timestamp; - _logger.info("Time for round trip: " + diff); + _logger.trace("Time for round trip: " + diff); } } } @@ -513,11 +545,9 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, pingNoWaitForReply(message, numPings, messageCorrelationId); CountDownLatch trafficLight = trafficLights.get(messageCorrelationId); - // Block the current thread until a reply to the message is received, or it times out. trafficLight.await(timeout, TimeUnit.MILLISECONDS); - // Remove the countdown latch from the map because the map is long lived, so will cause a memory leak. trafficLights.remove(messageCorrelationId); // Work out how many replies were receieved. @@ -532,6 +562,8 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _logger.info("Got all replies on id, " + messageCorrelationId); } + commitTx(getConsumerSession()); + return numReplies; } @@ -548,8 +580,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, * @return The reply, or null if no reply arrives before the timeout. * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ - public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) - throws JMSException, InterruptedException + public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException, InterruptedException { // Create a count down latch to count the number of replies with. This is created before the message is sent // so that the message is not received before the count down is created. @@ -647,6 +678,11 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, return _replyDestination; } + protected void setReplyDestination(Destination destination) + { + _replyDestination = destination; + } + public void setMessageListener(MessageListener messageListener) { _messageListener = messageListener; @@ -657,33 +693,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, return trafficLights.get(correlationID); } - protected Session getConsumerSession() - { - return _consumerSession; - } - - protected void setPingDestination(Destination destination) - { - _pingDestination = destination; - } - - protected void setReplyDestination(Destination destination) - { - _replyDestination = destination; - } - - private void createPingDestination(String name) - { - if (isPubSub()) - { - _pingDestination = new AMQTopic(name); - } - else - { - _pingDestination = new AMQQueue(name); - } - } - /* * When the test is being performed with multiple queues, then this method will be used, which has a loop to * pick up the next queue from the queues list and sends message to it. @@ -717,10 +726,12 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, public static class FailoverNotifier implements ConnectionListener { public void bytesSent(long count) - { } + { + } public void bytesReceived(long count) - { } + { + } public boolean preFailover(boolean redirect) { -- cgit v1.2.1 From 9068179bbf1ca717621bc993e66ecfcafbb3d959 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 24 Jan 2007 15:41:48 +0000 Subject: QPID-50 : Patch supplied by Rob Godfrey - Virtual Host implementation git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499446 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java index cbdd498b37..57512929c1 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java @@ -104,7 +104,7 @@ public class ServiceRequestingClient implements ExceptionListener m.getPropertyNames(); if (m.propertyExists("timeSent")) { - long timeSent = Long.parseLong(m.getStringProperty("timeSent")); + long timeSent = m.getLongProperty("timeSent"); if (_averageLatency == 0) { _averageLatency = _messageReceivedTime - timeSent; -- cgit v1.2.1 From 3033dd6d8f7c9748ec193709dc30c222908ce178 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Wed, 24 Jan 2007 16:14:36 +0000 Subject: added some constant values git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499461 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/ping/TestPingItself.java | 33 +++------- .../apache/qpid/requestreply/PingPongProducer.java | 75 +++++++++++++++------- 2 files changed, 63 insertions(+), 45 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java index e7515b0f78..acb0135b86 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java @@ -20,13 +20,11 @@ package org.apache.qpid.ping; import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.ObjectMessage; -import javax.jms.MessageListener; import org.apache.log4j.Logger; import org.apache.qpid.requestreply.PingPongProducer; import org.apache.qpid.topic.Config; -import org.apache.qpid.util.concurrent.BooleanLatch; /** * This class is used to test sending and receiving messages to (pingQueue) and from a queue (replyQueue). @@ -72,7 +70,7 @@ public class TestPingItself extends PingPongProducer messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, noOfDestinations, rate, pubsub); - if (noOfDestinations > 0) + if (noOfDestinations > DEFAULT_DESTINATION_COUNT) { createDestinations(noOfDestinations); _persistent = persistent; @@ -119,9 +117,9 @@ public class TestPingItself extends PingPongProducer boolean persistent = config.usePersistentMessages(); int messageSize = (config.getPayload() != 0) ? config.getPayload() : DEFAULT_MESSAGE_SIZE; int messageCount = config.getMessages(); - int destCount = (config.getDestinationsCount() != 0) ? config.getDestinationsCount() : 1; - int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : BATCH_SIZE; - int rate = (config.getRate() != 0) ? config.getRate() : 0; + int destCount = (config.getDestinationsCount() != 0) ? config.getDestinationsCount() : DEFAULT_DESTINATION_COUNT; + int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : DEFAULT_BATCH_SIZE; + int rate = (config.getRate() != 0) ? config.getRate() : DEFAULT_RATE; boolean pubsub = config.isPubSub(); String destName = config.getDestination(); @@ -129,16 +127,6 @@ public class TestPingItself extends PingPongProducer { destName = PING_DESTINATION_NAME; } - if (destCount > 1) - { - _logger.info("Destination Count:" + destCount + ", Transacted:" + transacted + ", persistent:" + - persistent + ",Message Size:" + messageSize + " bytes, pubsub:" + pubsub); - } - else - { - _logger.info("Destination:" + destName + ", Transacted:" + transacted + ", persistent:" + - persistent + ",Message Size:" + messageSize + " bytes, pubsub:" + pubsub); - } boolean afterCommit = false; boolean beforeCommit = false; @@ -193,17 +181,16 @@ public class TestPingItself extends PingPongProducer // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. pingItself.getConnection().setExceptionListener(pingItself); - if ((destCount > 1) || (messageCount > 0)) + if ((destCount > DEFAULT_DESTINATION_COUNT) || (messageCount > 0)) { - ObjectMessage msg = pingItself.getTestMessage(null, messageSize, persistent); - - // Send the message and wait for a reply. - int numReplies = pingItself.pingAndWaitForReply(msg, messageCount, TIMEOUT); - - _logger.info(("Messages Sent = " + messageCount + ", MessagesReceived = " + numReplies)); + _logger.info("Destinations Count:" + destCount + ", Transacted:" + transacted + ", persistent:" + + persistent + ",Message Size:" + messageSize + " bytes, pubsub:" + pubsub); + pingItself.pingLoop(); } else { + _logger.info("Destination:" + destName + ", Transacted:" + transacted + ", persistent:" + + persistent + ",Message Size:" + messageSize + " bytes, pubsub:" + pubsub); // set the message count to 0 to run this loop // Run a few priming pings to remove warm up time from test results. pingItself.prime(PRIMING_LOOPS); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index da63a6ae96..be46c1805b 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -40,6 +40,7 @@ import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; import org.apache.qpid.ping.AbstractPingProducer; import org.apache.qpid.ping.Throttle; +import org.apache.qpid.topic.Config; /** * PingPongProducer is a client that sends pings to a queue and waits for pongs to be bounced back by a bounce back @@ -75,6 +76,11 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, */ protected static final int DEFAULT_MESSAGE_SIZE = 0; + /** This is set and used when the test is for multiple-destinations */ + protected static final int DEFAULT_DESTINATION_COUNT = 0; + + protected static final int DEFAULT_RATE = 0; + /** * Used to define how long to wait between pings. */ @@ -93,7 +99,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, /** * The batch size. */ - protected static final int BATCH_SIZE = 100; + protected static final int DEFAULT_BATCH_SIZE = 100; protected static final int PREFETCH = 100; protected static final boolean NO_LOCAL = true; @@ -187,7 +193,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // total rate = throttle rate * batch size. // 1 < throttle rate < 100 // 1 < total rate < 20000 - if (rate > 0) + if (rate > DEFAULT_RATE) { // Log base 10 over 2 is used here to get a feel for what power of 100 the total rate is. // As the total rate goes up the powers of 100 the batch size goes up by powers of 100 to keep the @@ -228,7 +234,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _destinationCount = noOfDestinations; setPubSub(pubsub); - if (noOfDestinations == 0) + if (noOfDestinations == DEFAULT_DESTINATION_COUNT) { if (destinationName != null) { @@ -265,7 +271,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, */ public void createProducer() throws JMSException { - if (getDestinationsCount() > 1) + if (getDestinationsCount() > DEFAULT_DESTINATION_COUNT) { // create producer with initial destination as null for test with multiple-destinations // In this case, a different destination will be used while sending the message @@ -354,23 +360,33 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, public static void main(String[] args) throws Exception { // Extract the command line. - if (args.length < 2) + Config config = new Config(); + config.setOptions(args); + if (args.length == 0) { - System.err.println("Usage: TestPingPublisher [verbose (true/false)] " + - "[transacted (true/false)] [persistent (true/false)] [message size in bytes] [batchsize]" + - " [rate] [pubsub(true/false)]"); - System.exit(0); + _logger.info("Running test with default values..."); + //usage(); + //System.exit(0); } - String brokerDetails = args[0]; - String virtualpath = args[1]; - boolean verbose = (args.length >= 3) ? Boolean.parseBoolean(args[2]) : true; - boolean transacted = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; - boolean persistent = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; - int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; - int batchSize = (args.length >= 7) ? Integer.parseInt(args[6]) : 1; - int rate = (args.length >= 8) ? Integer.parseInt(args[7]) : 0; - boolean ispubsub = (args.length >= 9) ? Boolean.parseBoolean(args[8]) : false; + String brokerDetails = config.getHost() + ":" + config.getPort(); + String virtualpath = "/test"; + String selector = config.getSelector(); + boolean verbose = true; + boolean transacted = config.isTransacted(); + boolean persistent = config.usePersistentMessages(); + int messageSize = (config.getPayload() != 0) ? config.getPayload() : DEFAULT_MESSAGE_SIZE; + //int messageCount = config.getMessages(); + int destCount = (config.getDestinationsCount() != 0) ? config.getDestinationsCount() : DEFAULT_DESTINATION_COUNT; + int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : DEFAULT_BATCH_SIZE; + int rate = (config.getRate() != 0) ? config.getRate() : DEFAULT_RATE; + boolean pubsub = config.isPubSub(); + + String destName = config.getDestination(); + if (destName == null) + { + destName = PING_DESTINATION_NAME; + } boolean afterCommit = false; boolean beforeCommit = false; @@ -412,9 +428,9 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Create a ping producer to handle the request/wait/reply cycle. PingPongProducer pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, - PING_DESTINATION_NAME, null, transacted, persistent, messageSize, verbose, + destName, selector, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, - 0, rate, ispubsub); + destCount, rate, pubsub); pingProducer.getConnection().start(); @@ -432,6 +448,21 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, pingThread.join(); } + private static void usage() + { + System.err.println("Usage: TestPingPublisher \n" + "-host : broker host" + "-port : broker port" + + "-destinationname : queue/topic name\n" + + "-transacted : (true/false). Default is false\n" + + "-persistent : (true/false). Default is false\n" + + "-pubsub : (true/false). Default is false\n" + + "-selector : selector string\n" + + "-payload : paylaod size. Default is 0\n" + + //"-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)\n" + + "-destinationscount : no of destinations for multi-destinations test\n" + + "-batchsize : batch size\n" + + "-rate : thruput rate\n"); + } + /** * Primes the test loop by sending a few messages, then introduces a short wait. This allows the bounce back client * on the other end a chance to configure its reply producer on the reply to destination. It is also worth calling @@ -605,7 +636,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Check if the test is with multiple-destinations, in which case round robin the destinations // as the messages are sent. - if (getDestinationsCount() > 1) + if (getDestinationsCount() > DEFAULT_DESTINATION_COUNT) { sendMessage(getDestination(i % getDestinationsCount()), message); } @@ -656,7 +687,7 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, msg.setLongProperty("timestamp", System.currentTimeMillis()); // Send the message and wait for a reply. - pingAndWaitForReply(msg, BATCH_SIZE, TIMEOUT); + pingAndWaitForReply(msg, DEFAULT_BATCH_SIZE, TIMEOUT); // Introduce a short pause if desired. pause(SLEEP_TIME); -- cgit v1.2.1 From 48332965a98fb8ac51323205ac644ce8b9e3757e Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 25 Jan 2007 10:04:52 +0000 Subject: Race condition fixed fro AsyncTestPerf git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499716 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongProducer.java | 85 +++++++++++++--------- 1 file changed, 50 insertions(+), 35 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index be46c1805b..1368f631fb 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -76,7 +76,9 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, */ protected static final int DEFAULT_MESSAGE_SIZE = 0; - /** This is set and used when the test is for multiple-destinations */ + /** + * This is set and used when the test is for multiple-destinations + */ protected static final int DEFAULT_DESTINATION_COUNT = 0; protected static final int DEFAULT_RATE = 0; @@ -202,10 +204,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _throttleBatchSize = (int) Math.pow(100, x); int throttleRate = rate / _throttleBatchSize; - _logger.info("rate = " + rate); - _logger.info("x = " + x); - _logger.info("_throttleBatchSize = " + _throttleBatchSize); - _logger.info("throttleRate = " + throttleRate); + _logger.debug("rate = " + rate); + _logger.debug("x = " + x); + _logger.debug("_throttleBatchSize = " + _throttleBatchSize); + _logger.debug("throttleRate = " + throttleRate); rateLimiter = new Throttle(); rateLimiter.setRate(throttleRate); @@ -519,6 +521,11 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, if (trafficLight != null) { + if (_messageListener != null) + { + _messageListener.onMessage(message); + } + _logger.trace("Reply was expected, decrementing the latch for the id."); trafficLight.countDown(); @@ -529,11 +536,6 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, commitTx(getConsumerSession()); } - if (_messageListener != null) - { - _messageListener.onMessage(message); - } - } else { @@ -570,32 +572,39 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, */ public int pingAndWaitForReply(Message message, int numPings, long timeout) throws JMSException, InterruptedException { - // Put a unique correlation id on the message before sending it. - String messageCorrelationId = Long.toString(getNewID()); + String messageCorrelationId = null; - pingNoWaitForReply(message, numPings, messageCorrelationId); + try + { + // Put a unique correlation id on the message before sending it. + messageCorrelationId = Long.toString(getNewID()); - CountDownLatch trafficLight = trafficLights.get(messageCorrelationId); - // Block the current thread until a reply to the message is received, or it times out. - trafficLight.await(timeout, TimeUnit.MILLISECONDS); + pingNoWaitForReply(message, numPings, messageCorrelationId); - trafficLights.remove(messageCorrelationId); + CountDownLatch trafficLight = trafficLights.get(messageCorrelationId); + // Block the current thread until a reply to the message is received, or it times out. + trafficLight.await(timeout, TimeUnit.MILLISECONDS); - // Work out how many replies were receieved. - int numReplies = numPings - (int) trafficLight.getCount(); + // Work out how many replies were receieved. + int numReplies = numPings - (int) trafficLight.getCount(); - if ((numReplies < numPings) && _verbose) - { - _logger.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); + if ((numReplies < numPings) && _verbose) + { + _logger.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); + } + else if (_verbose) + { + _logger.info("Got all replies on id, " + messageCorrelationId); + } + + commitTx(getConsumerSession()); + + return numReplies; } - else if (_verbose) + finally { - _logger.info("Got all replies on id, " + messageCorrelationId); + removeLock(messageCorrelationId); } - - commitTx(getConsumerSession()); - - return numReplies; } public long getNewID() @@ -603,14 +612,20 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, return idGenerator.incrementAndGet(); } + public CountDownLatch removeLock(String correlationID) + { + return trafficLights.remove(correlationID); + } + + /* - * Sends the specified ping message but does not wait for a correlating reply. - * - * @param message The message to send. - * @param numPings The number of pings to send. - * @return The reply, or null if no reply arrives before the timeout. - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - */ + * Sends the specified ping message but does not wait for a correlating reply. + * + * @param message The message to send. + * @param numPings The number of pings to send. + * @return The reply, or null if no reply arrives before the timeout. + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + */ public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException, InterruptedException { // Create a count down latch to count the number of replies with. This is created before the message is sent -- cgit v1.2.1 From 8f4ddae2e04c9e690389e703f0d6e428e085abbb Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 25 Jan 2007 12:08:17 +0000 Subject: (Submitted by Rupert Smith) Class has been documented. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499756 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/AbstractPingClient.java | 141 +++++++++++++++------ 1 file changed, 105 insertions(+), 36 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java index da40f73608..c16213a92e 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java @@ -1,9 +1,28 @@ +/* + * + * 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.qpid.ping; -import java.text.SimpleDateFormat; import java.io.IOException; +import java.text.SimpleDateFormat; -import javax.jms.Connection; import javax.jms.JMSException; import org.apache.log4j.Logger; @@ -12,51 +31,52 @@ import org.apache.qpid.client.AMQConnection; import org.apache.qpid.jms.Session; /** - * Provides functionality common to all ping clients. Provides the ability to manage a session and a convenience method - * to commit on the current transaction. - *

    + * Provides common functionality that ping clients can use. This base class keeps track of the connection used to send + * pings, provides a convenience method to commit a transaction only when a session to commit on is transactional, keeps + * track of whether the ping client is pinging to a queue or a topic, provides prompts to the console to terminate brokers + * before and after commits, in order to test failover functionality, and provides a convience formatter for outputing + * readable timestamps for pings. + * *

    *
    CRC Card
    Responsibilities Collaborations - *
    Commit the current transcation. + *
    Commit the current transcation on a session. + *
    Generate failover promts. + *
    Keep track the connection. + *
    Keep track of p2p or topic ping type. *
    - * - * @author Rupert Smith */ public abstract class AbstractPingClient { - /** Used to format time stamping output. */ + private static final Logger _logger = Logger.getLogger(TestPingClient.class); + + /** A convenient formatter to use when time stamping output. */ protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); - private static final Logger _logger = Logger.getLogger(TestPingClient.class); + /** Holds the connection to the broker. */ private AMQConnection _connection; - /** tells if the test is being done for pubsub or p2p */ + + /** Flag used to indicate if this is a point to point or pub/sub ping client. */ private boolean _isPubSub = false; + /** + * This flag is used to indicate that the user should be prompted to kill a broker, in order to test + * failover, immediately before committing a transaction. + */ protected boolean _failBeforeCommit = false; - protected boolean _failAfterCommit = false; - - public AMQConnection getConnection() - { - return _connection; - } - public void setConnection(AMQConnection _connection) - { - this._connection = _connection; - } - - public void setPubSub(boolean pubsub) - { - _isPubSub = pubsub; - } - - public boolean isPubSub() - { - return _isPubSub; - } + /** + * This flag is used to indicate that the user should be prompted to a kill a broker, in order to test + * failover, immediate after committing a transaction. + */ + protected boolean _failAfterCommit = false; /** - * Convenience method to commit the transaction on the session associated with this bounce back client. + * Convenience method to commit the transaction on the specified session. If the session to commit on is not + * a transactional session, this method does nothing. + * + *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the + * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker + * after the commit is applied. * * @throws javax.jms.JMSException If the commit fails and then the rollback fails. */ @@ -102,6 +122,12 @@ public abstract class AbstractPingClient } } + /** + * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + * + * @param broker The name of the broker to terminate. + */ protected void doFailover(String broker) { System.out.println("Kill Broker " + broker + " now."); @@ -110,11 +136,15 @@ public abstract class AbstractPingClient System.in.read(); } catch (IOException e) - { - } + { } + System.out.println("Continuing."); } + /** + * Prompts the user to terminate the broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + */ protected void doFailover() { System.out.println("Kill Broker now."); @@ -123,10 +153,49 @@ public abstract class AbstractPingClient System.in.read(); } catch (IOException e) - { - } + { } + System.out.println("Continuing."); } + /** + * Gets the underlying connection that this ping client is running on. + * + * @return The underlying connection that this ping client is running on. + */ + public AMQConnection getConnection() + { + return _connection; + } + + /** + * Sets the connection that this ping client is using. + * + * @param _connection The ping connection. + */ + public void setConnection(AMQConnection _connection) + { + this._connection = _connection; + } + + /** + * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic. + * + * @param pubsub true if this client is pinging a topic, false if it is pinging a queue. + */ + public void setPubSub(boolean pubsub) + { + _isPubSub = pubsub; + } + + /** + * Checks whether this client is a p2p or pub/sub ping client. + * + * @return true if this client is pinging a topic, false if it is pinging a queue. + */ + public boolean isPubSub() + { + return _isPubSub; + } } -- cgit v1.2.1 From 805c3d03b5e7226f3e3e02bcc94c83bf87c905e0 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 25 Jan 2007 12:13:44 +0000 Subject: (Submitted by Rupert Smith) Class has been documented. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499757 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/ping/AbstractPingClient.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java index c16213a92e..c1dd5b18ad 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java @@ -31,11 +31,11 @@ import org.apache.qpid.client.AMQConnection; import org.apache.qpid.jms.Session; /** - * Provides common functionality that ping clients can use. This base class keeps track of the connection used to send - * pings, provides a convenience method to commit a transaction only when a session to commit on is transactional, keeps - * track of whether the ping client is pinging to a queue or a topic, provides prompts to the console to terminate brokers - * before and after commits, in order to test failover functionality, and provides a convience formatter for outputing - * readable timestamps for pings. + * Provides common functionality that ping clients (the recipients of ping messages) can use. This base class keeps + * track of the connection used to send pings, provides a convenience method to commit a transaction only when a session + * to commit on is transactional, keeps track of whether the ping client is pinging to a queue or a topic, provides + * prompts to the console to terminate brokers before and after commits, in order to test failover functionality, and + * provides a convience formatter for outputing readable timestamps for pings. * *

    *
    CRC Card
    Responsibilities Collaborations @@ -44,6 +44,9 @@ import org.apache.qpid.jms.Session; *
    Keep track the connection. *
    Keep track of p2p or topic ping type. *
    + * + * @todo This base class does not seem particularly usefull and some methods are duplicated in {@link AbstractPingProducer}, + * consider merging it into that class. */ public abstract class AbstractPingClient { -- cgit v1.2.1 From 4e1da8706dc8302caa7f97e29ac7cc33a60b5bb3 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 25 Jan 2007 12:46:22 +0000 Subject: (Submitted by Rupert Smith) Class has been documented. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499764 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/AbstractPingClient.java | 10 +- .../org/apache/qpid/ping/AbstractPingProducer.java | 256 +++++++++++++++------ 2 files changed, 191 insertions(+), 75 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java index c1dd5b18ad..97b411323e 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java @@ -45,8 +45,8 @@ import org.apache.qpid.jms.Session; *

    Keep track of p2p or topic ping type. *
    * - * @todo This base class does not seem particularly usefull and some methods are duplicated in {@link AbstractPingProducer}, - * consider merging it into that class. + * @todo This base class does not seem particularly usefull and all functionality is duplicated in {@link AbstractPingProducer}. + * Merge it into that class. */ public abstract class AbstractPingClient { @@ -175,11 +175,11 @@ public abstract class AbstractPingClient /** * Sets the connection that this ping client is using. * - * @param _connection The ping connection. + * @param connection The ping connection. */ - public void setConnection(AMQConnection _connection) + public void setConnection(AMQConnection connection) { - this._connection = _connection; + this._connection = connection; } /** diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java index debaa0d785..091a865473 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java @@ -1,3 +1,23 @@ +/* + * + * 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.qpid.ping; import java.io.IOException; @@ -13,6 +33,7 @@ import javax.jms.Message; import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQNoConsumersException; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; @@ -21,84 +42,105 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.jms.Session; /** - * This abstract class captures functionality that is common to all ping producers. It provides functionality to - * manage a session, and a convenience method to commit a transaction on the session. It also provides a framework - * for running a ping loop, and terminating that loop on exceptions or a shutdown handler. - *

    + * Provides common functionality that ping producers (the senders of ping messages) can use. This base class keeps + * track of the connection used to send pings; provides a convenience method to commit a transaction only when a session + * to commit on is transactional; keeps track of whether the ping client is pinging to a queue or a topic; provides + * prompts to the console to terminate brokers before and after commits, in order to test failover functionality; + * requires sub-classes to implement a ping loop, that this provides a run loop to repeatedly call; provides a + * default shutdown hook to cleanly terminate the run loop; keeps track of the destinations to send pings to; + * provides a convenience method to generate short pauses; and provides a convience formatter for outputing readable + * timestamps for pings. + * *

    *
    CRC Card
    Responsibilities Collaborations - *
    Manage the connection. - *
    Provide clean shutdown on exception or shutdown hook. - *
    Provide useable shutdown hook implementation. - *
    Run a ping loop. + *
    Commit the current transcation on a session. + *
    Generate failover promts. + *
    Keep track the connection. + *
    Keep track of p2p or topic ping type. + *
    Call ping loop to repeatedly send pings. + *
    Provide a shutdown hook. + *
    Generate short pauses. *
    * - * @author Rupert Smith + * @todo Destination count versus list of desintations is redundant. Use _destinions.size() to get the count and + * use a list of 1 destination when only 1 is needed. It is only important to distinguish when 1 destination + * is shared between multiple ping producers on the same JVM or if each ping producer has its own single + * destination. + * + * @todo Timestamp messages in nanos, not millis. Millis seems to have bad resolution, at least on windows. */ public abstract class AbstractPingProducer implements Runnable, ExceptionListener { private static final Logger _logger = Logger.getLogger(AbstractPingProducer.class); - /** tells if the test is being done for pubsub or p2p */ + /** Flag used to indicate if this is a point to point or pub/sub ping client. */ private boolean _isPubSub = false; - /** - * Used to format time stamping output. - */ - protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); - /** This id generator is used to generate ids to append to the queue name to ensure that queues are unique. */ - private static AtomicInteger _queueSequenceID = new AtomicInteger(); + /** A convenient formatter to use when time stamping output. */ + protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); /** - * Used to tell the ping loop when to terminate, it only runs while this is true. + * This id generator is used to generate ids to append to the queue name to ensure that queues can be unique when + * creating multiple ping producers in the same JVM. */ + private static AtomicInteger _queueSequenceID = new AtomicInteger(); + + /** Used to tell the ping loop when to terminate, it only runs while this is true. */ protected boolean _publish = true; - /** - * Holds the connection handle to the broker. - */ + /** Holds the connection to the broker. */ private Connection _connection; - /** - * Holds the producer session, need to create test messages. - */ + /** Holds the producer session, needed to create ping messages. */ private Session _producerSession; - /** - * Holds the number of destinations for multiple-destination test. By default it will be 1 - */ + /** Holds the number of destinations that this ping producer will send pings to, defaulting to a single destination. */ protected int _destinationCount = 1; - /** list of all the destinations for multiple-destinations test */ + /** Holds the set of destiniations that this ping producer pings. */ private List _destinations = new ArrayList(); - /** - * Holds the message producer to send the pings through. - */ + /** Holds the message producer to send the pings through. */ protected org.apache.qpid.jms.MessageProducer _producer; + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ protected boolean _failBeforeCommit = false; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ protected boolean _failAfterCommit = false; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ protected boolean _failBeforeSend = false; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ protected boolean _failAfterSend = false; + + /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ protected boolean _failOnce = true; /** Holds the number of sends that should be performed in every transaction when using transactions. */ protected int _txBatchSize = 1; /** - * Sets the test for pubsub or p2p. - * @param value + * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic. + * + * @param pubsub true if this client is pinging a topic, false if it is pinging a queue. */ - public void setPubSub(boolean value) + public void setPubSub(boolean pubsub) { - _isPubSub = value; + _isPubSub = pubsub; } + /** + * Checks whether this client is a p2p or pub/sub ping client. + * + * @return true if this client is pinging a topic, false if it is pinging a queue. + */ public boolean isPubSub() { return _isPubSub; } + /** * Convenience method for a short pause. * @@ -124,10 +166,11 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene public abstract void pingLoop(); /** - * Generates a test message of the specified size. + * Generates a test message of the specified size, with the specified reply-to destination and persistence flag. * * @param replyQueue The reply-to destination for the message. * @param messageSize The desired size of the message in bytes. + * @param persistent true if the message should use persistent delivery, false otherwise. * * @return A freshly generated test message. * @@ -138,6 +181,7 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene ObjectMessage msg = TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); // Timestamp the message. msg.setLongProperty("timestamp", System.currentTimeMillis()); + return msg; } @@ -191,85 +235,119 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene }); } + /** + * Gets the underlying connection that this ping client is running on. + * + * @return The underlying connection that this ping client is running on. + */ public Connection getConnection() { return _connection; } + /** + * Sets the connection that this ping client is using. + * + * @param connection The ping connection. + */ public void setConnection(Connection connection) { this._connection = connection; } + /** + * Gets the producer session that the ping client is using to send pings on. + * + * @return The producer session that the ping client is using to send pings on. + */ public Session getProducerSession() { return _producerSession; } + /** + * Keeps track of the producer session that the ping client is using to send pings on. + * + * @param session The producer session that the ping client is using to send pings on. + */ public void setProducerSession(Session session) { this._producerSession = session; } + /** + * Gets the number of destinations that this ping client is sending to. + * + * @return The number of destinations that this ping client is sending to. + */ public int getDestinationsCount() { return _destinationCount; } + /** + * Sets the number of destination that this ping client should send to. + * + * @param count The number of destination that this ping client should send to. + * + * @deprectaed Use _destinations.size() instead. + */ public void setDestinationsCount(int count) { this._destinationCount = count; } + /** + * Commits the transaction on the producer session. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + * + * @deprecated Use the commitTx(Session session) method instead, to explicitly specify which session is being + * committed. This makes it more obvious what is going on. + */ protected void commitTx() throws JMSException { commitTx(getProducerSession()); } /** - * Creates destinations dynamically and adds to the destinations list for multiple-destinations test - * @param count + * Creates the specified number of destinations to send pings to. Topics or Queues will be created depending on + * the value of the {@link #_isPubSub} flag. + * + * @param count The number of ping destinations to create. */ protected void createDestinations(int count) { - if (isPubSub()) - { - createTopics(count); - } - else - { - createQueues(count); - } - } - - private void createQueues(int count) - { + // Create the desired number of ping destinations. for (int i = 0; i < count; i++) { - AMQShortString name = - new AMQShortString("AMQQueue_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); - AMQQueue queue = new AMQQueue(name, name, false, false, false); - - _destinations.add(queue); - } - } + AMQDestination destination = null; - private void createTopics(int count) - { - for (int i = 0; i < count; i++) - { - AMQShortString name = - new AMQShortString("AMQTopic_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); - AMQTopic topic = new AMQTopic(name); + // Check if this is a pub/sub pinger, in which case create topics. + if (isPubSub()) + { + AMQShortString name = + new AMQShortString("AMQTopic_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); + destination = new AMQTopic(name); + } + // Otherwise this is a p2p pinger, in which case create queues. + else + { + AMQShortString name = + new AMQShortString("AMQQueue_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); + destination = new AMQQueue(name, name, false, false, false); + } - _destinations.add(topic); + _destinations.add(destination); } } /** - * Returns the destination from the destinations list with given index. This is for multiple-destinations test - * @param index - * @return Destination with given index + * Returns the destination from the destinations list with the given index. + * + * @param index The index of the destination to get. + * + * @return Destination with the given index. */ protected Destination getDestination(int index) { @@ -277,8 +355,21 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene } /** - * Convenience method to commit the transaction on the session associated with this pinger. + * Convenience method to commit the transaction on the specified session. If the session to commit on is not + * a transactional session, this method does nothing (unless the failover after send flag is set). + * + *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit + * is applied. This flag applies whether the pinger is transactional or not. + * + *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the + * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker + * after the commit is applied. These flags will only apply if using a transactional pinger. + * * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + * + * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit + * method, because commits only apply to transactional pingers, but fail after send applied to transactional + * and non-transactional alike. */ protected void commitTx(Session session) throws JMSException { @@ -351,11 +442,27 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene } } + /** + * Sends the specified message to the default destination of the ping producer. + * + * @param message The message to send. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + */ protected void sendMessage(Message message) throws JMSException { sendMessage(null, message); } + /** + * Sends the message to the specified destination. If the destination is null, it gets sent to the default destination + * of the ping producer. If an explicit destination is set, this overrides the default. + * + * @param destination The destination to send to. + * @param message The message to send. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + */ protected void sendMessage(Destination destination, Message message) throws JMSException { if (_failBeforeSend) @@ -376,9 +483,15 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene else { _producer.send(destination, message); - } + } } + /** + * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + * + * @param broker The name of the broker to terminate. + */ protected void doFailover(String broker) { System.out.println("Kill Broker " + broker + " now then press return"); @@ -392,6 +505,10 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene System.out.println("Continuing."); } + /** + * Prompts the user to terminate the broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + */ protected void doFailover() { System.out.println("Kill Broker now then press return"); @@ -403,6 +520,5 @@ public abstract class AbstractPingProducer implements Runnable, ExceptionListene { } System.out.println("Continuing."); - } } -- cgit v1.2.1 From 03352ba3222172c05dd946dc51a87c5077b93ea0 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 25 Jan 2007 13:08:05 +0000 Subject: Fixed race condition that would cause duplicate batch data to be logged. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@499781 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/requestreply/PingPongProducer.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 1368f631fb..263e62cf04 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -505,8 +505,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, */ public void onMessage(Message message) { + try { + // Store the reply, if it has a correlation id that is expected. String correlationID = message.getJMSCorrelationID(); @@ -523,11 +525,18 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, { if (_messageListener != null) { - _messageListener.onMessage(message); + synchronized (trafficLight) + { + _messageListener.onMessage(message); + trafficLight.countDown(); + } + } + else + { + trafficLight.countDown(); } _logger.trace("Reply was expected, decrementing the latch for the id."); - trafficLight.countDown(); long remainingCount = trafficLight.getCount(); -- cgit v1.2.1 From 81e67dcd13dcf238841d1591cfdc3f77bc62ab48 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Tue, 30 Jan 2007 16:40:20 +0000 Subject: (Submitted by Rupert Smith) Ping tests refactored. Unused ping test classes removed. JUnit-toolkit 0.5-SNAPSHOT added to the build. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@501455 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/AbstractPingClient.java | 204 ---- .../org/apache/qpid/ping/AbstractPingProducer.java | 524 --------- .../java/org/apache/qpid/ping/TestPingClient.java | 192 ---- .../java/org/apache/qpid/ping/TestPingItself.java | 223 ---- .../org/apache/qpid/ping/TestPingProducer.java | 249 ----- .../org/apache/qpid/ping/TestPingPublisher.java | 197 ---- .../org/apache/qpid/ping/TestPingSubscriber.java | 134 --- .../main/java/org/apache/qpid/ping/Throttle.java | 67 -- .../apache/qpid/requestreply/PingPongBouncer.java | 206 +++- .../apache/qpid/requestreply/PingPongProducer.java | 1137 +++++++++++++------- .../qpid/requestreply/ServiceProvidingClient.java | 235 ---- .../qpid/requestreply/ServiceRequestingClient.java | 428 -------- 12 files changed, 906 insertions(+), 2890 deletions(-) delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingPublisher.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java deleted file mode 100644 index 97b411323e..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingClient.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * - * 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.qpid.ping; - -import java.io.IOException; -import java.text.SimpleDateFormat; - -import javax.jms.JMSException; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.jms.Session; - -/** - * Provides common functionality that ping clients (the recipients of ping messages) can use. This base class keeps - * track of the connection used to send pings, provides a convenience method to commit a transaction only when a session - * to commit on is transactional, keeps track of whether the ping client is pinging to a queue or a topic, provides - * prompts to the console to terminate brokers before and after commits, in order to test failover functionality, and - * provides a convience formatter for outputing readable timestamps for pings. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Commit the current transcation on a session. - *
    Generate failover promts. - *
    Keep track the connection. - *
    Keep track of p2p or topic ping type. - *
    - * - * @todo This base class does not seem particularly usefull and all functionality is duplicated in {@link AbstractPingProducer}. - * Merge it into that class. - */ -public abstract class AbstractPingClient -{ - private static final Logger _logger = Logger.getLogger(TestPingClient.class); - - /** A convenient formatter to use when time stamping output. */ - protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); - - /** Holds the connection to the broker. */ - private AMQConnection _connection; - - /** Flag used to indicate if this is a point to point or pub/sub ping client. */ - private boolean _isPubSub = false; - - /** - * This flag is used to indicate that the user should be prompted to kill a broker, in order to test - * failover, immediately before committing a transaction. - */ - protected boolean _failBeforeCommit = false; - - /** - * This flag is used to indicate that the user should be prompted to a kill a broker, in order to test - * failover, immediate after committing a transaction. - */ - protected boolean _failAfterCommit = false; - - /** - * Convenience method to commit the transaction on the specified session. If the session to commit on is not - * a transactional session, this method does nothing. - * - *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the - * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker - * after the commit is applied. - * - * @throws javax.jms.JMSException If the commit fails and then the rollback fails. - */ - protected void commitTx(Session session) throws JMSException - { - if (session.getTransacted()) - { - try - { - if (_failBeforeCommit) - { - _logger.trace("Failing Before Commit"); - doFailover(); - } - - session.commit(); - - if (_failAfterCommit) - { - _logger.trace("Failing After Commit"); - doFailover(); - } - - _logger.trace("Session Commited."); - } - catch (JMSException e) - { - _logger.trace("JMSException on commit:" + e.getMessage(), e); - - try - { - session.rollback(); - _logger.debug("Message rolled back."); - } - catch (JMSException jmse) - { - _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); - - // Both commit and rollback failed. Throw the rollback exception. - throw jmse; - } - } - } - } - - /** - * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block - * until the user supplied some input on the terminal. - * - * @param broker The name of the broker to terminate. - */ - protected void doFailover(String broker) - { - System.out.println("Kill Broker " + broker + " now."); - try - { - System.in.read(); - } - catch (IOException e) - { } - - System.out.println("Continuing."); - } - - /** - * Prompts the user to terminate the broker, in order to test failover functionality. This method will block - * until the user supplied some input on the terminal. - */ - protected void doFailover() - { - System.out.println("Kill Broker now."); - try - { - System.in.read(); - } - catch (IOException e) - { } - - System.out.println("Continuing."); - - } - - /** - * Gets the underlying connection that this ping client is running on. - * - * @return The underlying connection that this ping client is running on. - */ - public AMQConnection getConnection() - { - return _connection; - } - - /** - * Sets the connection that this ping client is using. - * - * @param connection The ping connection. - */ - public void setConnection(AMQConnection connection) - { - this._connection = connection; - } - - /** - * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic. - * - * @param pubsub true if this client is pinging a topic, false if it is pinging a queue. - */ - public void setPubSub(boolean pubsub) - { - _isPubSub = pubsub; - } - - /** - * Checks whether this client is a p2p or pub/sub ping client. - * - * @return true if this client is pinging a topic, false if it is pinging a queue. - */ - public boolean isPubSub() - { - return _isPubSub; - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java deleted file mode 100644 index 091a865473..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/AbstractPingProducer.java +++ /dev/null @@ -1,524 +0,0 @@ -/* - * - * 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.qpid.ping; - -import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.jms.*; -import javax.jms.Connection; -import javax.jms.Message; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQNoConsumersException; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.message.TestMessageFactory; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.jms.Session; - -/** - * Provides common functionality that ping producers (the senders of ping messages) can use. This base class keeps - * track of the connection used to send pings; provides a convenience method to commit a transaction only when a session - * to commit on is transactional; keeps track of whether the ping client is pinging to a queue or a topic; provides - * prompts to the console to terminate brokers before and after commits, in order to test failover functionality; - * requires sub-classes to implement a ping loop, that this provides a run loop to repeatedly call; provides a - * default shutdown hook to cleanly terminate the run loop; keeps track of the destinations to send pings to; - * provides a convenience method to generate short pauses; and provides a convience formatter for outputing readable - * timestamps for pings. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Commit the current transcation on a session. - *
    Generate failover promts. - *
    Keep track the connection. - *
    Keep track of p2p or topic ping type. - *
    Call ping loop to repeatedly send pings. - *
    Provide a shutdown hook. - *
    Generate short pauses. - *
    - * - * @todo Destination count versus list of desintations is redundant. Use _destinions.size() to get the count and - * use a list of 1 destination when only 1 is needed. It is only important to distinguish when 1 destination - * is shared between multiple ping producers on the same JVM or if each ping producer has its own single - * destination. - * - * @todo Timestamp messages in nanos, not millis. Millis seems to have bad resolution, at least on windows. - */ -public abstract class AbstractPingProducer implements Runnable, ExceptionListener -{ - private static final Logger _logger = Logger.getLogger(AbstractPingProducer.class); - - /** Flag used to indicate if this is a point to point or pub/sub ping client. */ - private boolean _isPubSub = false; - - /** A convenient formatter to use when time stamping output. */ - protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); - - /** - * This id generator is used to generate ids to append to the queue name to ensure that queues can be unique when - * creating multiple ping producers in the same JVM. - */ - private static AtomicInteger _queueSequenceID = new AtomicInteger(); - - /** Used to tell the ping loop when to terminate, it only runs while this is true. */ - protected boolean _publish = true; - - /** Holds the connection to the broker. */ - private Connection _connection; - - /** Holds the producer session, needed to create ping messages. */ - private Session _producerSession; - - /** Holds the number of destinations that this ping producer will send pings to, defaulting to a single destination. */ - protected int _destinationCount = 1; - - /** Holds the set of destiniations that this ping producer pings. */ - private List _destinations = new ArrayList(); - - /** Holds the message producer to send the pings through. */ - protected org.apache.qpid.jms.MessageProducer _producer; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ - protected boolean _failBeforeCommit = false; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ - protected boolean _failAfterCommit = false; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ - protected boolean _failBeforeSend = false; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ - protected boolean _failAfterSend = false; - - /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ - protected boolean _failOnce = true; - - /** Holds the number of sends that should be performed in every transaction when using transactions. */ - protected int _txBatchSize = 1; - - /** - * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic. - * - * @param pubsub true if this client is pinging a topic, false if it is pinging a queue. - */ - public void setPubSub(boolean pubsub) - { - _isPubSub = pubsub; - } - - /** - * Checks whether this client is a p2p or pub/sub ping client. - * - * @return true if this client is pinging a topic, false if it is pinging a queue. - */ - public boolean isPubSub() - { - return _isPubSub; - } - - /** - * Convenience method for a short pause. - * - * @param sleepTime The time in milliseconds to pause for. - */ - public static void pause(long sleepTime) - { - if (sleepTime > 0) - { - try - { - Thread.sleep(sleepTime); - } - catch (InterruptedException ie) - { } - } - } - - /** - * Implementations should provide this method to perform a single ping cycle (which may send many messages). The - * run loop will repeatedly call this method until the publish flag is set to false. - */ - public abstract void pingLoop(); - - /** - * Generates a test message of the specified size, with the specified reply-to destination and persistence flag. - * - * @param replyQueue The reply-to destination for the message. - * @param messageSize The desired size of the message in bytes. - * @param persistent true if the message should use persistent delivery, false otherwise. - * - * @return A freshly generated test message. - * - * @throws JMSException All underlying JMSException are allowed to fall through. - */ - public ObjectMessage getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException - { - ObjectMessage msg = TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); - // Timestamp the message. - msg.setLongProperty("timestamp", System.currentTimeMillis()); - - return msg; - } - - /** - * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this - * flag has been cleared. - */ - public void stop() - { - _publish = false; - } - - /** - * Implements a ping loop that repeatedly pings until the publish flag becomes false. - */ - public void run() - { - // Keep running until the publish flag is cleared. - while (_publish) - { - pingLoop(); - } - } - - /** - * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the - * connection, this clears the publish flag which in turn will halt the ping loop. - * - * @param e The exception that triggered this callback method. - */ - public void onException(JMSException e) - { - _publish = false; - _logger.debug("There was a JMSException: " + e.getMessage(), e); - } - - /** - * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered - * with the runtime system as a shutdown hook. - * - * @return A shutdown hook for the ping loop. - */ - public Thread getShutdownHook() - { - return new Thread(new Runnable() - { - public void run() - { - stop(); - } - }); - } - - /** - * Gets the underlying connection that this ping client is running on. - * - * @return The underlying connection that this ping client is running on. - */ - public Connection getConnection() - { - return _connection; - } - - /** - * Sets the connection that this ping client is using. - * - * @param connection The ping connection. - */ - public void setConnection(Connection connection) - { - this._connection = connection; - } - - /** - * Gets the producer session that the ping client is using to send pings on. - * - * @return The producer session that the ping client is using to send pings on. - */ - public Session getProducerSession() - { - return _producerSession; - } - - /** - * Keeps track of the producer session that the ping client is using to send pings on. - * - * @param session The producer session that the ping client is using to send pings on. - */ - public void setProducerSession(Session session) - { - this._producerSession = session; - } - - /** - * Gets the number of destinations that this ping client is sending to. - * - * @return The number of destinations that this ping client is sending to. - */ - public int getDestinationsCount() - { - return _destinationCount; - } - - /** - * Sets the number of destination that this ping client should send to. - * - * @param count The number of destination that this ping client should send to. - * - * @deprectaed Use _destinations.size() instead. - */ - public void setDestinationsCount(int count) - { - this._destinationCount = count; - } - - /** - * Commits the transaction on the producer session. - * - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - * - * @deprecated Use the commitTx(Session session) method instead, to explicitly specify which session is being - * committed. This makes it more obvious what is going on. - */ - protected void commitTx() throws JMSException - { - commitTx(getProducerSession()); - } - - /** - * Creates the specified number of destinations to send pings to. Topics or Queues will be created depending on - * the value of the {@link #_isPubSub} flag. - * - * @param count The number of ping destinations to create. - */ - protected void createDestinations(int count) - { - // Create the desired number of ping destinations. - for (int i = 0; i < count; i++) - { - AMQDestination destination = null; - - // Check if this is a pub/sub pinger, in which case create topics. - if (isPubSub()) - { - AMQShortString name = - new AMQShortString("AMQTopic_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); - destination = new AMQTopic(name); - } - // Otherwise this is a p2p pinger, in which case create queues. - else - { - AMQShortString name = - new AMQShortString("AMQQueue_" + _queueSequenceID.incrementAndGet() + "_" + System.currentTimeMillis()); - destination = new AMQQueue(name, name, false, false, false); - } - - _destinations.add(destination); - } - } - - /** - * Returns the destination from the destinations list with the given index. - * - * @param index The index of the destination to get. - * - * @return Destination with the given index. - */ - protected Destination getDestination(int index) - { - return _destinations.get(index); - } - - /** - * Convenience method to commit the transaction on the specified session. If the session to commit on is not - * a transactional session, this method does nothing (unless the failover after send flag is set). - * - *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit - * is applied. This flag applies whether the pinger is transactional or not. - * - *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the - * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker - * after the commit is applied. These flags will only apply if using a transactional pinger. - * - * @throws javax.jms.JMSException If the commit fails and then the rollback fails. - * - * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit - * method, because commits only apply to transactional pingers, but fail after send applied to transactional - * and non-transactional alike. - */ - protected void commitTx(Session session) throws JMSException - { - _logger.trace("Batch time reached"); - if (_failAfterSend) - { - _logger.trace("Batch size reached"); - if (_failOnce) - { - _failAfterSend = false; - } - - _logger.trace("Failing After Send"); - doFailover(); - } - - if (session.getTransacted()) - { - try - { - if (_failBeforeCommit) - { - if (_failOnce) - { - _failBeforeCommit = false; - } - - _logger.trace("Failing Before Commit"); - doFailover(); - } - - session.commit(); - - if (_failAfterCommit) - { - if (_failOnce) - { - _failAfterCommit = false; - } - - _logger.trace("Failing After Commit"); - doFailover(); - } - - _logger.trace("Session Commited."); - } - catch (JMSException e) - { - _logger.trace("JMSException on commit:" + e.getMessage(), e); - - // Warn that the bounce back client is not available. - if (e.getLinkedException() instanceof AMQNoConsumersException) - { - _logger.debug("No consumers on queue."); - } - - try - { - session.rollback(); - _logger.trace("Message rolled back."); - } - catch (JMSException jmse) - { - _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); - - // Both commit and rollback failed. Throw the rollback exception. - throw jmse; - } - } - } - } - - /** - * Sends the specified message to the default destination of the ping producer. - * - * @param message The message to send. - * - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - */ - protected void sendMessage(Message message) throws JMSException - { - sendMessage(null, message); - } - - /** - * Sends the message to the specified destination. If the destination is null, it gets sent to the default destination - * of the ping producer. If an explicit destination is set, this overrides the default. - * - * @param destination The destination to send to. - * @param message The message to send. - * - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - */ - protected void sendMessage(Destination destination, Message message) throws JMSException - { - if (_failBeforeSend) - { - if (_failOnce) - { - _failBeforeSend = false; - } - - _logger.trace("Failing Before Send"); - doFailover(); - } - - if (destination == null) - { - _producer.send(message); - } - else - { - _producer.send(destination, message); - } - } - - /** - * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block - * until the user supplied some input on the terminal. - * - * @param broker The name of the broker to terminate. - */ - protected void doFailover(String broker) - { - System.out.println("Kill Broker " + broker + " now then press return"); - try - { - System.in.read(); - } - catch (IOException e) - { } - - System.out.println("Continuing."); - } - - /** - * Prompts the user to terminate the broker, in order to test failover functionality. This method will block - * until the user supplied some input on the terminal. - */ - protected void doFailover() - { - System.out.println("Kill Broker now then press return"); - try - { - System.in.read(); - } - catch (IOException e) - { } - - System.out.println("Continuing."); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java deleted file mode 100644 index 949ace20e1..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingClient.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * - * 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.qpid.ping; - -import java.net.InetAddress; - -import javax.jms.*; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.jms.Session; - -/** - * PingClient is a message listener that received time stamped ping messages. It can work out how long a ping took, - * provided that its clokc is synchronized to that of the ping producer, or by running it on the same machine (or jvm) - * as the ping producer. - *

    - *

    There is a verbose mode flag which causes information about each ping to be output to the console - * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should - * be disabled for real timing tests as writing to the console will slow things down. - *

    - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Provide command line invocation to start the ping consumer on a configurable broker url. - *
    - * - * @todo Add a better command line interpreter to the main method. The command line is not very nice... - */ -class TestPingClient extends AbstractPingClient implements MessageListener -{ - private static final Logger _logger = Logger.getLogger(TestPingClient.class); - - /** - * Used to indicate that the reply generator should log timing info to the console (logger info level). - */ - private boolean _verbose = false; - - /** - * The producer session. - */ - private Session _consumerSession; - - /** - * Creates a TestPingClient on the specified session. - * - * @param brokerDetails - * @param username - * @param password - * @param queueName - * @param virtualpath - * @param transacted - * @param selector - * @param verbose - * @param afterCommit - *@param beforeCommit @throws Exception All underlying exceptions allowed to fall through. This is only test code... - */ - public TestPingClient(String brokerDetails, String username, String password, String queueName, String virtualpath, - boolean transacted, String selector, boolean verbose, boolean afterCommit, boolean beforeCommit) throws Exception - { - // Create a connection to the broker. - InetAddress address = InetAddress.getLocalHost(); - String clientID = address.getHostName() + System.currentTimeMillis(); - - setConnection(new AMQConnection(brokerDetails, username, password, clientID, virtualpath)); - - // Create a transactional or non-transactional session depending on the command line parameter. - _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); - - // Connect a consumer to the ping queue and register this to be called back by it. - Queue q = new AMQQueue(queueName); - MessageConsumer consumer = _consumerSession.createConsumer(q, 1, false, false, selector); - - consumer.setMessageListener(this); - - // Hang on to the verbose flag setting. - _verbose = verbose; - - // Set failover interrupts - _failAfterCommit = afterCommit; - _failBeforeCommit = beforeCommit; - } - - /** - * Starts a stand alone ping-pong client running in verbose mode. - * - * @param args - */ - public static void main(String[] args) throws Exception - { - _logger.info("Starting..."); - - // Display help on the command line. - if (args.length < 4) - { - System.out.println( - "Usage: brokerdetails username password virtual-path [queueName] [verbose] [transacted] [selector] [failover::commit]"); - System.exit(1); - } - - // Extract all command line parameters. - String brokerDetails = args[0]; - String username = args[1]; - String password = args[2]; - String virtualpath = args[3]; - String queueName = (args.length >= 5) ? args[4] : "ping"; - boolean verbose = (args.length >= 6) ? Boolean.parseBoolean(args[5]) : true; - boolean transacted = (args.length >= 7) ? Boolean.parseBoolean(args[6]) : false; - String selector = (args.length == 8) ? args[7] : null; - - boolean afterCommit = false; - boolean beforeCommit = false; - - for (String arg : args) - { - if (arg.startsWith("failover:")) - { - //failover:: - String[] parts = arg.split(":"); - if (parts.length == 3) - { - if (parts[2].equals("commit")) - { - afterCommit = parts[1].equals("after"); - beforeCommit = parts[1].equals("before"); - } - } - else - { - System.out.println("Unrecognized failover request:" + arg); - } - } - } - - // Create the test ping client and set it running. - TestPingClient pingClient = - new TestPingClient(brokerDetails, username, password, queueName, virtualpath, transacted, selector, verbose, afterCommit, beforeCommit); - - pingClient.getConnection().start(); - - System.out.println("Waiting..."); - } - /** - * This is a callback method that is notified of all messages for which this has been registered as a message - * listener on a message consumer. - * - * @param message The message that triggered this callback. - */ - public void onMessage(javax.jms.Message message) - { - try - { - // Spew out some timing information if verbose mode is on. - if (_verbose) - { - Long timestamp = message.getLongProperty("timestamp"); - - if (timestamp != null) - { - long diff = System.currentTimeMillis() - timestamp; - System.out.println("Ping time: " + diff); - } - } - - // Commit the transaction if running in transactional mode. - commitTx(_consumerSession); - } - catch (JMSException e) - { - _logger.error("There was a JMSException: " + e.getMessage(), e); - } - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java deleted file mode 100644 index acb0135b86..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingItself.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed 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.qpid.ping; - -import javax.jms.JMSException; -import javax.jms.MessageConsumer; -import javax.jms.ObjectMessage; - -import org.apache.log4j.Logger; - -import org.apache.qpid.requestreply.PingPongProducer; -import org.apache.qpid.topic.Config; - -/** - * This class is used to test sending and receiving messages to (pingQueue) and from a queue (replyQueue). - * The producer and consumer created by this test send and receive messages to and from the same Queue. ie. - * pingQueue and replyQueue are same. - * This class extends @see org.apache.qpid.requestreply.PingPongProducer which different ping and reply Queues - */ -public class TestPingItself extends PingPongProducer -{ - private static final Logger _logger = Logger.getLogger(TestPingItself.class); - - /** - * If noOfDestinations is <= 1 : There will be one Queue and one consumer instance for the test - * If noOfDestinations is > 1 : This creats a client for tests with multiple queues. Creates as many consumer instances - * as there are queues, each listening to a Queue. A producer is created which picks up a queue from - * the list of queues to send message - * - * @param brokerDetails - * @param username - * @param password - * @param virtualpath - * @param queueName - * @param selector - * @param transacted - * @param persistent - * @param messageSize - * @param verbose - * @param afterCommit - * @param beforeCommit - * @param afterSend - * @param beforeSend - * @param failOnce - * @param batchSize - * @param noOfDestinations - * @throws Exception - */ - public TestPingItself(String brokerDetails, String username, String password, String virtualpath, String queueName, - String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, - boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, - int batchSize, int noOfDestinations, int rate, boolean pubsub) throws Exception - { - super(brokerDetails, username, password, virtualpath, queueName, selector, transacted, persistent, - messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, - noOfDestinations, rate, pubsub); - - if (noOfDestinations > DEFAULT_DESTINATION_COUNT) - { - createDestinations(noOfDestinations); - _persistent = persistent; - _messageSize = messageSize; - _verbose = verbose; - - createConsumers(selector); - createProducer(); - } - } - - /** - * Sets the replyQueue to be the same as ping queue. - */ - @Override - public void createConsumer(String selector) throws JMSException - { - // Create a message consumer to get the replies with and register this to be called back by it. - setReplyDestination(getPingDestination()); - MessageConsumer consumer = - getConsumerSession().createConsumer(getReplyDestination(), PREFETCH, false, EXCLUSIVE, selector); - consumer.setMessageListener(this); - } - - /** - * Starts a ping-pong loop running from the command line. - * - * @param args The command line arguments as defined above. - */ - public static void main(String[] args) throws Exception - { - // Extract the command line. - Config config = new Config(); - config.setOptions(args); - if (args.length == 0) - { - _logger.info("Running test with default values..."); - } - - String brokerDetails = config.getHost() + ":" + config.getPort(); - String virtualpath = "/test"; - boolean verbose = true; - boolean transacted = config.isTransacted(); - boolean persistent = config.usePersistentMessages(); - int messageSize = (config.getPayload() != 0) ? config.getPayload() : DEFAULT_MESSAGE_SIZE; - int messageCount = config.getMessages(); - int destCount = (config.getDestinationsCount() != 0) ? config.getDestinationsCount() : DEFAULT_DESTINATION_COUNT; - int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : DEFAULT_BATCH_SIZE; - int rate = (config.getRate() != 0) ? config.getRate() : DEFAULT_RATE; - boolean pubsub = config.isPubSub(); - - String destName = config.getDestination(); - if (destName == null) - { - destName = PING_DESTINATION_NAME; - } - - boolean afterCommit = false; - boolean beforeCommit = false; - boolean afterSend = false; - boolean beforeSend = false; - boolean failOnce = false; - - for (String arg : args) - { - if (arg.startsWith("failover:")) - { - //failover:: - String[] parts = arg.split(":"); - if (parts.length == 3) - { - if (parts[2].equals("commit")) - { - afterCommit = parts[1].equals("after"); - beforeCommit = parts[1].equals("before"); - } - - if (parts[2].equals("send")) - { - afterSend = parts[1].equals("after"); - beforeSend = parts[1].equals("before"); - } - - if (parts[1].equals("once")) - { - failOnce = true; - } - - } - else - { - System.out.println("Unrecognized failover request:" + arg); - } - } - } - - // Create a ping producer to handle the request/wait/reply cycle. - TestPingItself pingItself = new TestPingItself(brokerDetails, "guest", "guest", virtualpath, destName, null, - transacted, persistent, messageSize, verbose, afterCommit, - beforeCommit, afterSend, beforeSend, failOnce, batchSize, - destCount, rate, pubsub); - - pingItself.getConnection().start(); - - // Create a shutdown hook to terminate the ping-pong producer. - Runtime.getRuntime().addShutdownHook(pingItself.getShutdownHook()); - - // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. - pingItself.getConnection().setExceptionListener(pingItself); - - if ((destCount > DEFAULT_DESTINATION_COUNT) || (messageCount > 0)) - { - _logger.info("Destinations Count:" + destCount + ", Transacted:" + transacted + ", persistent:" + - persistent + ",Message Size:" + messageSize + " bytes, pubsub:" + pubsub); - pingItself.pingLoop(); - } - else - { - _logger.info("Destination:" + destName + ", Transacted:" + transacted + ", persistent:" + - persistent + ",Message Size:" + messageSize + " bytes, pubsub:" + pubsub); - // set the message count to 0 to run this loop - // Run a few priming pings to remove warm up time from test results. - pingItself.prime(PRIMING_LOOPS); - - _logger.info("Running the infinite loop and pinging the broker..."); - // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. - Thread pingThread = new Thread(pingItself); - pingThread.run(); - pingThread.join(); - } - - pingItself.getConnection().close(); - } - - private static void usage() - { - System.err.println("Usage: TestPingPublisher \n" + "-host : broker host" + "-port : broker port" + - "-destinationname : queue/topic name\n" + - "-transacted : (true/false). Default is false\n" + - "-persistent : (true/false). Default is false\n" + - "-pubsub : (true/false). Default is false\n" + - "-selector : selector string\n" + - "-payload : paylaod size. Default is 0\n" + - "-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)\n" + - "-destinationscount : no of destinations for multi-destinations test\n" + - "-batchsize : batch size\n" + - "-rate : thruput rate\n"); - System.exit(0); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java deleted file mode 100644 index d9e81d39de..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingProducer.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * - * 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.qpid.ping; - -import java.net.InetAddress; -import java.text.SimpleDateFormat; -import java.util.Date; - -import javax.jms.*; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.jms.MessageProducer; -import org.apache.qpid.jms.Session; - -/** - * PingProducer is a client that sends timestamped pings to a queue. It is designed to be run from the command line - * as a stand alone test tool, but it may also be fairly easily instantiated by other code by supplying a session and - * configured message producer. - *

    - *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop - * does all its work through helper methods, so that code wishing to run a ping cycle is not forced to do so - * by starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is - * also registered to terminate the ping loop cleanly. - *

    - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Provide a ping cycle. - *
    Provide command line invocation to loop the ping cycle on a configurable broker url. - *
    - */ -class TestPingProducer extends AbstractPingProducer -{ - private static final Logger _logger = Logger.getLogger(TestPingProducer.class); - - /** - * Used to set up a default message size. - */ - private static final int DEFAULT_MESSAGE_SIZE = 0; - - /** - * Used to define how long to wait between pings. - */ - private static final long SLEEP_TIME = 250; - - /** - * Holds the name of the queue to send pings on. - */ - private static final String PING_QUEUE_NAME = "ping"; - - private static TestPingProducer _pingProducer; - - /** - * Determines whether this producer sends persistent messages from the run method. - */ - private boolean _persistent = false; - - /** - * Holds the message size to send, from the run method. - */ - private int _messageSize = DEFAULT_MESSAGE_SIZE; - - /** - * Used to indicate that the ping loop should print out whenever it pings. - */ - private boolean _verbose = false; - - public TestPingProducer(String brokerDetails, String username, String password, String virtualpath, String queueName, - boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, - boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize) - throws Exception - { - // Create a connection to the broker. - InetAddress address = InetAddress.getLocalHost(); - String clientID = address.getHostName() + System.currentTimeMillis(); - - setConnection(new AMQConnection(brokerDetails, username, password, clientID, virtualpath)); - - // Create a transactional or non-transactional session, based on the command line arguments. - setProducerSession((Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE)); - - // Create a queue to send the pings on. - Queue pingQueue = new AMQQueue(queueName); - _producer = (MessageProducer) getProducerSession().createProducer(pingQueue); - - _persistent = persistent; - _messageSize = messageSize; - - _verbose = verbose; - - // Set failover interrupts - _failAfterCommit = afterCommit; - _failBeforeCommit = beforeCommit; - _failAfterSend = afterSend; - _failBeforeSend = beforeSend; - _txBatchSize = batchSize; - _failOnce = failOnce; - } - - /** - * Starts a ping-pong loop running from the command line. The bounce back client {@link TestPingClient} also needs - * to be started to bounce the pings back again. - * - * @param args The command line arguments as defined above. - */ - public static void main(String[] args) throws Exception - { - // Extract the command line. - if (args.length < 2) - { - System.err.println( - "Usage: TestPingPublisher " - + "[ "); - System.exit(0); - } - - String brokerDetails = args[0]; - String virtualpath = args[1]; - boolean verbose = (args.length >= 3) ? Boolean.parseBoolean(args[2]) : true; - boolean transacted = (args.length >= 4) ? Boolean.parseBoolean(args[3]) : false; - boolean persistent = (args.length >= 5) ? Boolean.parseBoolean(args[4]) : false; - int messageSize = (args.length >= 6) ? Integer.parseInt(args[5]) : DEFAULT_MESSAGE_SIZE; - int batchSize = (args.length >= 7) ? Integer.parseInt(args[6]) : 1; - - boolean afterCommit = false; - boolean beforeCommit = false; - boolean afterSend = false; - boolean beforeSend = false; - boolean failOnce = false; - - for (String arg : args) - { - if (arg.startsWith("failover:")) - { - //failover:: - String[] parts = arg.split(":"); - if (parts.length == 3) - { - if (parts[2].equals("commit")) - { - afterCommit = parts[1].equals("after"); - beforeCommit = parts[1].equals("before"); - } - - if (parts[2].equals("send")) - { - afterSend = parts[1].equals("after"); - beforeSend = parts[1].equals("before"); - } - - if (parts[1].equals("once")) - { - failOnce = true; - } - } - else - { - System.out.println("Unrecognized failover request:" + arg); - } - } - } - - // Create a ping producer to generate the pings. - _pingProducer = new TestPingProducer(brokerDetails, "guest", "guest", virtualpath, PING_QUEUE_NAME, transacted, - persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, - beforeSend, failOnce, batchSize); - - // Start the connection running. - _pingProducer.getConnection().start(); - - // Create a shutdown hook to terminate the ping-pong producer. - Runtime.getRuntime().addShutdownHook(_pingProducer.getShutdownHook()); - - // Ensure the ping loop execption listener is registered on the connection to terminate it on error. - _pingProducer.getConnection().setExceptionListener(_pingProducer); - - // Start the ping loop running until it is interrupted. - Thread pingThread = new Thread(_pingProducer); - pingThread.run(); - pingThread.join(); - } - - /** - * Sends the specified ping message. - * - * @param message The message to send. - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - */ - public void ping(Message message) throws JMSException - { - sendMessage(message); - - // Keep the messageId to correlate with the reply. - String messageId = message.getJMSMessageID(); - - // Commit the transaction if running in transactional mode. This must happen now, rather than at the end of - // this method, as the message will not be sent until the transaction is committed. - commitTx(); - } - - /** - * The ping loop implementation. This send out pings of the configured size, persistence and transactionality, and - * waits for short pauses in between each. - */ - public void pingLoop() - { - try - { - // Generate a sample message and time stamp it. - ObjectMessage msg = getTestMessage(null, _messageSize, _persistent); - msg.setLongProperty("timestamp", System.currentTimeMillis()); - - // Send the message. - ping(msg); - - if (_verbose) - { - System.out.println("Pinged at: " + timestampFormatter.format(new Date())); //" + " with id: " + msg.getJMSMessageID()); - } - // Introduce a short pause if desired. - pause(SLEEP_TIME); - } - catch (JMSException e) - { - _publish = false; - _logger.error("There was a JMSException: " + e.getMessage(), e); - } - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingPublisher.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingPublisher.java deleted file mode 100644 index 3b2dcc4d36..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingPublisher.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * - * 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.qpid.pingpong; - -import org.apache.log4j.Logger; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.AMQException; -import org.apache.qpid.url.URLSyntaxException; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.BasicMessageProducer; -import org.apache.qpid.client.message.TestMessageFactory; -import org.apache.qpid.jms.MessageProducer; -import org.apache.qpid.jms.Session; - -import javax.jms.*; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * A client that behaves as follows: - *

    • Connects to a queue, whose name is specified as a cmd-line argument
    • - *
    • Creates a temporary queue
    • - *
    • Creates messages containing a property that is the name of the temporary queue
    • - *
    • Fires off a message on the original queue and waits for a response on the temporary queue
    • - *
    - */ -public class TestPingPublisher implements ExceptionListener -{ - private static final Logger _log = Logger.getLogger(TestPingPublisher.class); - - private AMQConnection _connection; - - private boolean _publish; - private static int _messageSize = 0; - private long SLEEP_TIME = 0L; - -// private class CallbackHandler implements MessageListener -// { -// -// private int _actualMessageCount; -// -// -// public void onMessage(Message m) -// { -// if (_log.isDebugEnabled()) -// { -// _log.debug("Message received: " + m); -// } -// _actualMessageCount++; -// if (_actualMessageCount % 1000 == 0) -// { -// _log.info("Received message count: " + _actualMessageCount); -// } -// } -// } - - public TestPingPublisher(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException - { - try - { - createConnection(brokerDetails, clientID, virtualpath); - - Session session = (Session) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - //AMQQueue destination = new AMQQueue("ping"); - AMQTopic destination = new AMQTopic("ping"); - MessageProducer producer = (MessageProducer) session.createProducer(destination); - - _connection.setExceptionListener(this); - - _connection.start(); - - int msgCount = 0; - while (_publish) - { -/* - TextMessage msg = session.createTextMessage( - "Presented to in conjunction with Mahnah Mahnah and the Snowths: " + ++messageNumber); -*/ - ObjectMessage msg = null; - if (_messageSize != 0) - { - msg = TestMessageFactory.newObjectMessage(session, _messageSize); - } - else - { - msg = session.createObjectMessage(); - } - - Long time = System.nanoTime(); - msg.setStringProperty("timestampString", Long.toString(time)); - msg.setLongProperty("timestamp", time); - - ((BasicMessageProducer) producer).send(msg, DeliveryMode.PERSISTENT, true); - - _log.info("Message Sent:" + msgCount++); - _log.debug(msg); - - if (msgCount == Integer.MAX_VALUE) - { - _publish = false; - } - - if (SLEEP_TIME > 0) - { - try - { - Thread.sleep(SLEEP_TIME); - } - catch (InterruptedException ie) - { - //do nothing - } - } - } - - } - catch (JMSException e) - { - e.printStackTrace(); - } - } - - private void createConnection(String brokerDetails, String clientID, String virtualpath) throws AMQException, URLSyntaxException - { - _publish = true; - _connection = new AMQConnection(brokerDetails, "guest", "guest", clientID, virtualpath); - _log.info("Connected with URL:" + _connection.toURL()); - } - - /** - * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank - * means the server will allocate a name. - */ - public static void main(String[] args) - { - if (args.length < 2) - { - System.err.println("Usage: TestPingPublisher [message size in bytes]"); - System.exit(0); - } - try - { - InetAddress address = InetAddress.getLocalHost(); - String clientID = address.getHostName() + System.currentTimeMillis(); - if (args.length > 2 ) - { - _messageSize = Integer.parseInt(args[2]); - } - new TestPingPublisher(args[0], clientID, args[1]); - } - catch (UnknownHostException e) - { - e.printStackTrace(); - } - catch (AMQException e) - { - System.err.println("Error in client: " + e); - e.printStackTrace(); - } - catch (URLSyntaxException e) - { - System.err.println("Error in connection arguments : " + e); - } - - //System.exit(0); - } - - /** - * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) - */ - public void onException(JMSException e) - { - System.err.println(e.getMessage()); - - _publish = false; - e.printStackTrace(System.err); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java deleted file mode 100644 index b43319744a..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/TestPingSubscriber.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * - * 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.qpid.pingpong; - -import org.apache.log4j.Logger; -import org.apache.log4j.Level; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.jms.Session; - -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.Topic; -import javax.jms.JMSException; -import java.net.InetAddress; - -public class TestPingSubscriber -{ - private static final Logger _logger = Logger.getLogger(TestPingSubscriber.class); - - private static class TestPingMessageListener implements MessageListener - { - public TestPingMessageListener() - { - } - - long _lastTimestamp = 0L; - long _lastTimestampString = 0L; - - public void onMessage(javax.jms.Message message) - { - Long time = System.nanoTime(); - - if (_logger.isInfoEnabled()) - { - long timestampString = 0L; - - try - { - long timestamp = message.getLongProperty("timestamp"); - timestampString = Long.parseLong(message.getStringProperty("timestampString")); - - if (timestampString != timestamp) - { - _logger.info("Timetamps differ!:\n" + - "timestamp:" + timestamp + "\n" + - "timestampString:" + timestampString); - } - - } - catch (JMSException jmse) - { - _logger.error("JMSException caught:" + jmse.getMessage(), jmse); - } - - - long stringDiff = time - timestampString; - - _logger.info("Ping: TS:" + stringDiff / 1000 + "us"); - - // _logger.info(_name + " got message '" + message + "\n"); - } - } - } - - public static void main(String[] args) - { - _logger.info("Starting..."); - - if (args.length < 4) - { - System.out.println("Usage: brokerdetails username password virtual-path [selector] "); - System.exit(1); - } - try - { - InetAddress address = InetAddress.getLocalHost(); - AMQConnection con1 = new AMQConnection(args[0], args[1], args[2], - address.getHostName(), args[3]); - - _logger.info("Connected with URL:" + con1.toURL()); - - final org.apache.qpid.jms.Session session1 = (org.apache.qpid.jms.Session) - con1.createSession(false, Session.AUTO_ACKNOWLEDGE); - - - String selector = null; - - if (args.length == 5) - { - selector = args[4]; - _logger.info("Message selector is <" + selector + ">..."); - } - else - { - _logger.info("Not using message selector "); - } - - Topic t = new AMQTopic("ping"); - - MessageConsumer consumer1 = session1.createConsumer(t, - 1, false, false, selector); - - consumer1.setMessageListener(new TestPingMessageListener()); - con1.start(); - } - catch (Throwable t) - { - System.err.println("Fatal error: " + t); - t.printStackTrace(); - } - - System.out.println("Waiting..."); - } -} - diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java deleted file mode 100644 index 1e98e45bba..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/Throttle.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.apache.qpid.ping; - -/** - * Throttle is a helper class used in situations where a controlled rate of processing is desired. It allows a certain - * number of operations-per-second to be defined and supplies a {@link #throttle} method that can only be called at - * most at that rate. The first call to the throttle method will return immediately, subsequent calls will introduce - * a short pause to fill out the remainder of the current cycle to attain the desired rate. If there is no remainder - * left then it will return immediately. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    - * - * @author Rupert Smith - */ -public class Throttle -{ - /** Holds the length of the cycle in nano seconds. */ - long cycleLengthNanos = 0L; - - /** Records the nano time of the last call to the throttle method. */ - long lastTimeNanos = 0L; - - /** - * Sets up the desired rate of operation per second that the throttle method should restrict to. - * - * @param opsPerSecond The maximum number of calls per second that the throttle method will take. - */ - public void setRate(int opsPerSecond) - { - // Calculate the length of a cycle. - cycleLengthNanos = 1000000000 / opsPerSecond; - } - - /** - * Introduces a short pause to fill out any time left in the cycle since this method was last called, of length - * defined by a call to the {@link #setRate} method. - */ - public void throttle() - { - // Record the time now. - long currentTimeNanos = System.nanoTime(); - - // Check if there is any time remaining in the current cycle and introduce a short wait to fill out the - // remainder of the cycle if needed. - long remainingTimeNanos = cycleLengthNanos - (currentTimeNanos - lastTimeNanos); - - if (remainingTimeNanos > 0) - { - long milliWait = remainingTimeNanos / 1000000; - int nanoWait = (int) (remainingTimeNanos % 1000000); - - try - { - Thread.currentThread().sleep(milliWait, nanoWait); - } - catch (InterruptedException e) - { - // Just ignore this? - } - } - - // Keep the time of the last call to this method to calculate the next cycle. - //lastTimeNanos = currentTimeNanos; - lastTimeNanos = System.nanoTime(); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java index bae6aa0dc2..87edd31575 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -20,7 +20,9 @@ */ package org.apache.qpid.requestreply; +import java.io.IOException; import java.net.InetAddress; +import java.text.SimpleDateFormat; import java.util.Date; import javax.jms.*; @@ -32,7 +34,6 @@ import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; import org.apache.qpid.jms.ConnectionListener; import org.apache.qpid.jms.Session; -import org.apache.qpid.ping.AbstractPingClient; import org.apache.qpid.topic.Config; /** @@ -58,7 +59,7 @@ import org.apache.qpid.topic.Config; * * @todo Make verbose accept a number of messages, only prints to console every X messages. */ -public class PingPongBouncer extends AbstractPingClient implements MessageListener +public class PingPongBouncer implements MessageListener { private static final Logger _logger = Logger.getLogger(PingPongBouncer.class); @@ -73,6 +74,9 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen /** The default exclusive flag for the message consumer. */ private static final boolean EXCLUSIVE = false; + /** A convenient formatter to use when time stamping output. */ + protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); + /** Used to indicate that the reply generator should log timing info to the console (logger info level). */ private boolean _verbose = false; @@ -93,6 +97,24 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen /** The producer session. */ private Session _producerSession; + /** Holds the connection to the broker. */ + private AMQConnection _connection; + + /** Flag used to indicate if this is a point to point or pub/sub ping client. */ + private boolean _isPubSub = false; + + /** + * This flag is used to indicate that the user should be prompted to kill a broker, in order to test + * failover, immediately before committing a transaction. + */ + protected boolean _failBeforeCommit = false; + + /** + * This flag is used to indicate that the user should be prompted to a kill a broker, in order to test + * failover, immediate after committing a transaction. + */ + protected boolean _failAfterCommit = false; + /** * Creates a PingPongBouncer on the specified producer and consumer sessions. * @@ -110,8 +132,8 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen * @throws Exception All underlying exceptions allowed to fall through. This is only test code... */ public PingPongBouncer(String brokerDetails, String username, String password, String virtualpath, - String destinationName, boolean persistent, boolean transacted, String selector, - boolean verbose, boolean pubsub) throws Exception + String destinationName, boolean persistent, boolean transacted, String selector, boolean verbose, + boolean pubsub) throws Exception { // Create a client id to uniquely identify this client. InetAddress address = InetAddress.getLocalHost(); @@ -133,7 +155,8 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen // Create the queue to listen for message on. createConsumerDestination(destinationName); - MessageConsumer consumer = _consumerSession.createConsumer(_consumerDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); + MessageConsumer consumer = + _consumerSession.createConsumer(_consumerDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); // Create a producer for the replies, without a default destination. _replyProducer = _producerSession.createProducer(null); @@ -144,18 +167,6 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen consumer.setMessageListener(this); } - private void createConsumerDestination(String name) - { - if (isPubSub()) - { - _consumerDestination = new AMQTopic(name); - } - else - { - _consumerDestination = new AMQQueue(name); - } - } - /** * Starts a stand alone ping-pong client running in verbose mode. * @@ -177,12 +188,13 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen Config config = new Config(); config.setOptions(args); String brokerDetails = config.getHost() + ":" + config.getPort(); - String virtualpath = "/test"; + String virtualpath = "/test"; String destinationName = config.getDestination(); if (destinationName == null) { destinationName = DEFAULT_DESTINATION_NAME; } + String selector = config.getSelector(); boolean transacted = config.isTransacted(); boolean persistent = config.usePersistentMessages(); @@ -192,13 +204,22 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen //String selector = null; // Instantiate the ping pong client with the command line options and start it running. - PingPongBouncer pingBouncer = new PingPongBouncer(brokerDetails, "guest", "guest", virtualpath, - destinationName, persistent, transacted, selector, verbose, pubsub); + PingPongBouncer pingBouncer = + new PingPongBouncer(brokerDetails, "guest", "guest", virtualpath, destinationName, persistent, transacted, + selector, verbose, pubsub); pingBouncer.getConnection().start(); System.out.println("Waiting..."); } + private static void usage() + { + System.err.println("Usage: PingPongBouncer \n" + "-host : broker host\n" + "-port : broker port\n" + + "-destinationname : queue/topic name\n" + "-transacted : (true/false). Default is false\n" + + "-persistent : (true/false). Default is false\n" + + "-pubsub : (true/false). Default is false\n" + "-selector : selector string\n"); + } + /** * This is a callback method that is notified of all messages for which this has been registered as a message * listener on a message consumer. It sends a reply (pong) to all messages it receieves on the reply to @@ -260,14 +281,145 @@ public class PingPongBouncer extends AbstractPingClient implements MessageListen } } - private static void usage() + /** + * Gets the underlying connection that this ping client is running on. + * + * @return The underlying connection that this ping client is running on. + */ + public AMQConnection getConnection() + { + return _connection; + } + + /** + * Sets the connection that this ping client is using. + * + * @param connection The ping connection. + */ + public void setConnection(AMQConnection connection) + { + this._connection = connection; + } + + /** + * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic. + * + * @param pubsub true if this client is pinging a topic, false if it is pinging a queue. + */ + public void setPubSub(boolean pubsub) + { + _isPubSub = pubsub; + } + + /** + * Checks whether this client is a p2p or pub/sub ping client. + * + * @return true if this client is pinging a topic, false if it is pinging a queue. + */ + public boolean isPubSub() + { + return _isPubSub; + } + + /** + * Convenience method to commit the transaction on the specified session. If the session to commit on is not + * a transactional session, this method does nothing. + * + *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the + * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker + * after the commit is applied. + * + * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + */ + protected void commitTx(Session session) throws JMSException + { + if (session.getTransacted()) + { + try + { + if (_failBeforeCommit) + { + _logger.trace("Failing Before Commit"); + doFailover(); + } + + session.commit(); + + if (_failAfterCommit) + { + _logger.trace("Failing After Commit"); + doFailover(); + } + + _logger.trace("Session Commited."); + } + catch (JMSException e) + { + _logger.trace("JMSException on commit:" + e.getMessage(), e); + + try + { + session.rollback(); + _logger.debug("Message rolled back."); + } + catch (JMSException jmse) + { + _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); + + // Both commit and rollback failed. Throw the rollback exception. + throw jmse; + } + } + } + } + + /** + * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + * + * @param broker The name of the broker to terminate. + */ + protected void doFailover(String broker) + { + System.out.println("Kill Broker " + broker + " now."); + try + { + System.in.read(); + } + catch (IOException e) + { } + + System.out.println("Continuing."); + } + + /** + * Prompts the user to terminate the broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + */ + protected void doFailover() { - System.err.println("Usage: PingPongBouncer \n" + "-host : broker host\n" + "-port : broker port\n" + - "-destinationname : queue/topic name\n" + - "-transacted : (true/false). Default is false\n" + - "-persistent : (true/false). Default is false\n" + - "-pubsub : (true/false). Default is false\n" + - "-selector : selector string\n"); + System.out.println("Kill Broker now."); + try + { + System.in.read(); + } + catch (IOException e) + { } + + System.out.println("Continuing."); + + } + + private void createConsumerDestination(String name) + { + if (isPubSub()) + { + _consumerDestination = new AMQTopic(name); + } + else + { + _consumerDestination = new AMQQueue(name); + } } /** diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 263e62cf04..310ec5f5e3 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -20,344 +20,353 @@ */ package org.apache.qpid.requestreply; +import java.io.IOException; import java.net.InetAddress; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import javax.jms.*; import org.apache.log4j.Logger; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.jms.ConnectionListener; +import org.apache.qpid.client.*; +import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; -import org.apache.qpid.ping.AbstractPingProducer; -import org.apache.qpid.ping.Throttle; import org.apache.qpid.topic.Config; +import uk.co.thebadgerset.junit.extensions.BatchedThrottle; +import uk.co.thebadgerset.junit.extensions.Throttle; + /** * PingPongProducer is a client that sends pings to a queue and waits for pongs to be bounced back by a bounce back - * client (see {@link PingPongBouncer} for the bounce back client). It is designed to be run from the command line - * as a stand alone test tool, but it may also be fairly easily instantiated by other code by supplying a session, - * message producer and message consumer to run the ping-pong cycle on. - *

    + * client (see {@link PingPongBouncer} for the bounce back client). + * *

    The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. * This means that this class has to do some work to correlate pings with pongs; it expectes the original message - * id in the ping to be bounced back in the correlation id. If a new temporary queue per ping were used, then - * this correlation would not need to be done. - *

    + * correlation id in the ping to be bounced back in the reply correlation id. + * + *

    This ping tool accepts a vast number of configuration options, all of which are passed in to the constructor. + * It can ping topics or queues; ping multiple destinations; do persistent pings; send messages of any size; do pings + * within transactions; control the number of pings to send in each transaction; limit its sending rate; and perform + * failover testing. + * *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so * by starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is * also registered to terminate the ping-pong loop cleanly. - *

    + * *

    *
    CRC Card
    Responsibilities Collaborations - *
    Provide a ping and wait for response cycle. + *
    Provide a ping and wait for all responses cycle. *
    Provide command line invocation to loop the ping cycle on a configurable broker url. *
    * - * @todo Make temp queue per ping a command line option. - * @todo Make the queue name a command line option. + * @todo The use of a ping rate {@link #DEFAULT_RATE} and waits between pings {@link #DEFAULT_SLEEP_TIME} are overlapping. + * Use the rate and throttling only. + * + * @todo Make shared or unique destinations a configurable option, hard coded to false. */ -public class PingPongProducer extends AbstractPingProducer implements Runnable, MessageListener, ExceptionListener +public class PingPongProducer implements Runnable, MessageListener, ExceptionListener { private static final Logger _logger = Logger.getLogger(PingPongProducer.class); - /** - * Used to set up a default message size. - */ - protected static final int DEFAULT_MESSAGE_SIZE = 0; + /** Holds the name of the property to get the test message size from. */ + public static final String MESSAGE_SIZE_PROPNAME = "messagesize"; - /** - * This is set and used when the test is for multiple-destinations - */ - protected static final int DEFAULT_DESTINATION_COUNT = 0; + /** Holds the name of the property to get the ping queue name from. */ + public static final String PING_QUEUE_NAME_PROPNAME = "destinationname"; - protected static final int DEFAULT_RATE = 0; + /** Holds the name of the property to get the test delivery mode from. */ + public static final String PERSISTENT_MODE_PROPNAME = "persistent"; - /** - * Used to define how long to wait between pings. - */ - protected static final long SLEEP_TIME = 250; + /** Holds the name of the property to get the test transactional mode from. */ + public static final String TRANSACTED_PROPNAME = "transacted"; - /** - * Used to define how long to wait before assuming that a ping has timed out. - */ - protected static final long TIMEOUT = 9000; + /** Holds the name of the property to get the test broker url from. */ + public static final String BROKER_PROPNAME = "broker"; - /** - * Holds the name of the destination to send pings on. - */ - protected static final String PING_DESTINATION_NAME = "ping"; + /** Holds the name of the property to get the test broker virtual path. */ + public static final String VIRTUAL_PATH_PROPNAME = "virtualPath"; - /** - * The batch size. - */ - protected static final int DEFAULT_BATCH_SIZE = 100; + /** Holds the name of the property to get the message rate from. */ + public static final String RATE_PROPNAME = "rate"; - protected static final int PREFETCH = 100; - protected static final boolean NO_LOCAL = true; - protected static final boolean EXCLUSIVE = false; + public static final String VERBOSE_OUTPUT_PROPNAME = "verbose"; - /** - * The number of priming loops to run. - */ - protected static final int PRIMING_LOOPS = 3; + /** Holds the true or false depending on wether it is P2P test or PubSub */ + public static final String IS_PUBSUB_PROPNAME = "pubsub"; - /** - * A source for providing sequential unique correlation ids. - */ + public static final String FAIL_AFTER_COMMIT_PROPNAME = "FailAfterCommit"; + + public static final String FAIL_BEFORE_COMMIT_PROPNAME = "FailBeforeCommit"; + + public static final String FAIL_AFTER_SEND_PROPNAME = "FailAfterSend"; + + public static final String FAIL_BEFORE_SEND_PROPNAME = "FailBeforeSend"; + + public static final String FAIL_ONCE_PROPNAME = "FailOnce"; + + public static final String USERNAME_PROPNAME = "username"; + + public static final String PASSWORD_PROPNAME = "password"; + + public static final String SELECTOR_PROPNAME = "selector"; + + public static final String PING_DESTINATION_COUNT_PROPNAME = "destinationscount"; + + /** Holds the name of the property to get the waiting timeout for response messages. */ + public static final String TIMEOUT_PROPNAME = "timeout"; + + public static final String COMMIT_BATCH_SIZE_PROPNAME = "CommitBatchSize"; + + /** Used to set up a default message size. */ + public static final int DEFAULT_MESSAGE_SIZE = 0; + + /** Holds the name of the default destination to send pings on. */ + public static final String DEFAULT_PING_DESTINATION_NAME = "ping"; + + /** Defines the default number of destinations to ping. */ + public static final int DEFAULT_DESTINATION_COUNT = 1; + + /** Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. */ + public static final int DEFAULT_RATE = 0; + + /** Defines the default wait between pings. */ + public static final long DEFAULT_SLEEP_TIME = 250; + + /** Default time to wait before assuming that a ping has timed out. */ + public static final long DEFAULT_TIMEOUT = 9000; + + /** Defines the default number of pings to send in each transaction when running transactionally. */ + public static final int DEFAULT_TX_BATCH_SIZE = 100; + + /** Defines the default prefetch size to use when consuming messages. */ + public static final int DEFAULT_PREFETCH = 100; + + /** Defines the default value of the no local flag to use when consuming messages. */ + public static final boolean DEFAULT_NO_LOCAL = false; + + /** Defines the default value of the exclusive flag to use when consuming messages. */ + public static final boolean DEFAULT_EXCLUSIVE = false; + + /** Holds the message delivery mode to use for the test. */ + public static final boolean DEFAULT_PERSISTENT_MODE = false; + + /** Holds the transactional mode to use for the test. */ + public static final boolean DEFAULT_TRANSACTED = false; + + /** Holds the default broker url for the test. */ + public static final String DEFAULT_BROKER = "tcp://localhost:5672"; + + /** Holds the default virtual path for the test. */ + public static final String DEFAULT_VIRTUAL_PATH = "test"; + + /** Holds the pub/sub mode default, true means ping a topic, false means ping a queue. */ + public static final boolean DEFAULT_PUBSUB = false; + + /** Holds the default broker log on username. */ + public static final String DEFAULT_USERNAME = "guest"; + + /** Holds the default broker log on password. */ + public static final String DEFAULT_PASSWORD = "guest"; + + /** Holds the default message selector. */ + public static final String DEFAULT_SELECTOR = null; + + /** Holds the default failover after commit test flag. */ + public static final String DEFAULT_FAIL_AFTER_COMMIT = "false"; + + /** Holds the default failover before commit test flag. */ + public static final String DEFAULT_FAIL_BEFORE_COMMIT = "false"; + + /** Holds the default failover after send test flag. */ + public static final String DEFAULT_FAIL_AFTER_SEND = "false"; + + /** Holds the default failover before send test flag. */ + public static final String DEFAULT_FAIL_BEFORE_SEND = "false"; + + /** Holds the default failover only once flag, true means only do one failover, false means failover on every commit cycle. */ + public static final String DEFAULT_FAIL_ONCE = "true"; + + /** Holds the default verbose mode. */ + public static final boolean DEFAULT_VERBOSE = false; + + /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ private static AtomicLong idGenerator = new AtomicLong(0L); /** - * Holds a map from message ids to latches on which threads wait for replies. + * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross + * multiple ping producers on the same JVM. */ - private static Map trafficLights = new HashMap(); + private static Map trafficLights = + Collections.synchronizedMap(new HashMap()); + + /** A convenient formatter to use when time stamping output. */ + protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); /** - * Destination where the responses messages will arrive + * This id generator is used to generate ids to append to the queue name to ensure that queues can be unique when + * creating multiple ping producers in the same JVM. */ + protected static AtomicInteger _queueJVMSequenceID = new AtomicInteger(); + + /** Destination where the response messages will arrive. */ private Destination _replyDestination; - /** - * Destination where the producer will be sending message to - */ - private Destination _pingDestination; + /** Destination where the producer will be sending message to. */ + //private Destination _pingDestination; - /** - * Determines whether this producer sends persistent messages from the run method. - */ + /** Determines whether this producer sends persistent messages. */ protected boolean _persistent; - /** - * Holds the message size to send, from the run method. - */ + /** Determines what size of messages this producer sends. */ protected int _messageSize; - /** - * Used to indicate that the ping loop should print out whenever it pings. - */ + /** Used to indicate that the ping loop should print out whenever it pings. */ protected boolean _verbose = false; + /** Holds the session on which ping replies are received. */ protected Session _consumerSession; - /** - * Used to restrict the sending rate to a specified limit. - */ - private Throttle rateLimiter = null; + /** Used to restrict the sending rate to a specified limit. */ + private Throttle _rateLimiter = null; + + /** Holds a message listener that this message listener chains all its messages to. */ + private ChainedMessageListener _chainedMessageListener = null; + + /** Flag used to indicate if this is a point to point or pub/sub ping client. */ + protected boolean _isPubSub = false; /** - * The throttler can only reliably restrict to a few hundred cycles per second, so a throttling batch size is used - * to group sends together into batches large enough that the throttler runs slower than that. + * This id generator is used to generates ids that are only unique within this pinger. Creating multiple pingers + * on the same JVM using this id generator will allow them to ping on the same queues. */ - int _throttleBatchSize; + protected AtomicInteger _queueSharedId = new AtomicInteger(); - private MessageListener _messageListener = null; + /** Used to tell the ping loop when to terminate, it only runs while this is true. */ + protected boolean _publish = true; - private PingPongProducer(String brokerDetails, String username, String password, String virtualpath, boolean transacted, - boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, - boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, int rate) - throws Exception - { - // Create a connection to the broker. - InetAddress address = InetAddress.getLocalHost(); - String clientID = address.getHostName() + System.currentTimeMillis(); + /** Holds the connection to the broker. */ + private Connection _connection; - setConnection(new AMQConnection(brokerDetails, username, password, clientID, virtualpath)); + /** Holds the producer session, needed to create ping messages. */ + private Session _producerSession; - // Create transactional or non-transactional sessions, based on the command line arguments. - setProducerSession((Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE)); - _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + /** Holds the set of destiniations that this ping producer pings. */ + protected List _pingDestinations = new ArrayList(); - _persistent = persistent; - _messageSize = messageSize; - _verbose = verbose; + /** Holds the message producer to send the pings through. */ + protected MessageProducer _producer; - // Set failover interrupts - _failAfterCommit = afterCommit; - _failBeforeCommit = beforeCommit; - _failAfterSend = afterSend; - _failBeforeSend = beforeSend; - _failOnce = failOnce; - _txBatchSize = batchSize; - - // Calculate a throttling batch size and rate such that the throttle runs slower than 100 cycles per second - // and batched sends within each cycle multiply up to give the desired rate. - // - // total rate = throttle rate * batch size. - // 1 < throttle rate < 100 - // 1 < total rate < 20000 - if (rate > DEFAULT_RATE) - { - // Log base 10 over 2 is used here to get a feel for what power of 100 the total rate is. - // As the total rate goes up the powers of 100 the batch size goes up by powers of 100 to keep the - // throttle rate back into the range 1 to 100. - int x = (int) (Math.log10(rate) / 2); - _throttleBatchSize = (int) Math.pow(100, x); - int throttleRate = rate / _throttleBatchSize; - - _logger.debug("rate = " + rate); - _logger.debug("x = " + x); - _logger.debug("_throttleBatchSize = " + _throttleBatchSize); - _logger.debug("throttleRate = " + throttleRate); - - rateLimiter = new Throttle(); - rateLimiter.setRate(throttleRate); - } - } + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ + protected boolean _failBeforeCommit = false; - /** - * Creates a ping pong producer with the specified connection details and type. - * - * @param brokerDetails - * @param username - * @param password - * @param virtualpath - * @param transacted - * @throws Exception All allowed to fall through. This is only test code... - */ - public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, - String destinationName, String selector, boolean transacted, boolean persistent, - int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, - boolean afterSend, boolean beforeSend, boolean failOnce, int batchSize, - int noOfDestinations, int rate, boolean pubsub) throws Exception - { - this(brokerDetails, username, password, virtualpath, transacted, persistent, messageSize, verbose, afterCommit, - beforeCommit, afterSend, beforeSend, failOnce, batchSize, rate); + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ + protected boolean _failAfterCommit = false; - _destinationCount = noOfDestinations; - setPubSub(pubsub); + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ + protected boolean _failBeforeSend = false; - if (noOfDestinations == DEFAULT_DESTINATION_COUNT) - { - if (destinationName != null) - { - createPingDestination(destinationName); - // Create producer and the consumer - createProducer(); - createConsumer(selector); - } - else - { - _logger.error("Destination is not specified"); - throw new IllegalArgumentException("Destination is not specified"); - } - } - } + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ + protected boolean _failAfterSend = false; - private void createPingDestination(String name) - { - if (isPubSub()) - { - _pingDestination = new AMQTopic(name); - } - else - { - _pingDestination = new AMQQueue(name); - } - } + /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ + protected boolean _failOnce = true; + + /** Holds the number of sends that should be performed in every transaction when using transactions. */ + protected int _txBatchSize = 1; /** - * Creates the producer to send the pings on. If the tests are with nultiple-destinations, then producer - * is created with null destination, so that any destination can be specified while sending + * Creates a ping producer with the specified parameters, of which there are many. See their individual comments + * for details. This constructor creates a connection to the broker and creates producer and consumer sessions on it, + * to send and recieve its pings and replies on. The other options are kept, and control how this pinger behaves. * - * @throws JMSException + * @param brokerDetails The URL of the broker to send pings to. + * @param username The username to log onto the broker with. + * @param password The password to log onto the broker with. + * @param virtualpath The virtual host name to use on the broker. + * @param destinationName The name (or root where multiple destinations are used) of the desitination to send + * pings to. + * @param selector The selector to filter replies with. + * @param transacted Indicates whether or not pings are sent and received in transactions. + * @param persistent Indicates whether pings are sent using peristent delivery. + * @param messageSize Specifies the size of ping messages to send. + * @param verbose Indicates that information should be printed to the console on every ping. + * @param afterCommit Indicates that the user should be promted to terminate a broker after commits to test failover. + * @param beforeCommit Indicates that the user should be promted to terminate a broker before commits to test failover. + * @param afterSend Indicates that the user should be promted to terminate a broker after sends to test failover. + * @param beforeSend Indicates that the user should be promted to terminate a broker before sends to test failover. + * @param failOnce Indicates that the failover testing behaviour should only happen on the first commit, not all. + * @param txBatchSize Specifies the number of pings to send in each transaction. + * @param noOfDestinations The number of destinations to ping. Must be 1 or more. + * @param rate Specified the number of pings per second to send. Setting this to 0 means send as fast as + * possible, with no rate restriction. + * @param pubsub + * + * @throws Exception Any exceptions are allowed to fall through. */ - public void createProducer() throws JMSException + public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, + String destinationName, String selector, boolean transacted, boolean persistent, int messageSize, + boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, + boolean beforeSend, boolean failOnce, int txBatchSize, int noOfDestinations, int rate, + boolean pubsub) throws Exception { - if (getDestinationsCount() > DEFAULT_DESTINATION_COUNT) - { - // create producer with initial destination as null for test with multiple-destinations - // In this case, a different destination will be used while sending the message - _producer = (MessageProducer) getProducerSession().createProducer(null); - } - else + // Check that one or more destinations were specified. + if (noOfDestinations < 1) { - // Create a producer with known destination to send the pings on. - _producer = (MessageProducer) getProducerSession().createProducer(_pingDestination); - + throw new IllegalArgumentException("There must be at least one destination."); } - _producer.setDisableMessageTimestamp(true); - _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - } + // Create a connection to the broker. + InetAddress address = InetAddress.getLocalHost(); + String clientID = address.getHostName() + System.currentTimeMillis(); - /** - * Creates the temporary destination to listen to the responses - * - * @param selector - * @throws JMSException - */ - public void createConsumer(String selector) throws JMSException - { - // Create a temporary destination to get the pongs on. - if (isPubSub()) - { - _replyDestination = _consumerSession.createTemporaryTopic(); - } - else - { - _replyDestination = _consumerSession.createTemporaryQueue(); - } + _connection = new AMQConnection(brokerDetails, username, password, clientID, virtualpath); - // Create a message consumer to get the replies with and register this to be called back by it. - MessageConsumer consumer = _consumerSession.createConsumer(_replyDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); - consumer.setMessageListener(this); - } + // Create transactional or non-transactional sessions, based on the command line arguments. + _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); - /** - * Creates consumer instances for each destination. This is used when test is being done with multiple destinations. - * - * @param selector - * @throws JMSException - */ - public void createConsumers(String selector) throws JMSException - { - for (int i = 0; i < getDestinationsCount(); i++) + // Set up a throttle to control the send rate, if a rate > 0 is specified. + if (rate > 0) { - MessageConsumer consumer = - getConsumerSession().createConsumer(getDestination(i), PREFETCH, false, EXCLUSIVE, selector); - consumer.setMessageListener(this); + _rateLimiter = new BatchedThrottle(); + _rateLimiter.setRate(rate); } - } - - public Session getConsumerSession() - { - return _consumerSession; - } + // Create the temporary queue for replies. + _replyDestination = _consumerSession.createTemporaryQueue(); - public Destination getPingDestination() - { - return _pingDestination; - } + // Create the producer and the consumers for all reply destinations. + createProducer(); + createPingDestinations(noOfDestinations, selector, destinationName, true); + createReplyConsumers(getReplyDestinations(), selector); - protected void setPingDestination(Destination destination) - { - _pingDestination = destination; + // Keep all the remaining options. + _persistent = persistent; + _messageSize = messageSize; + _verbose = verbose; + _failAfterCommit = afterCommit; + _failBeforeCommit = beforeCommit; + _failAfterSend = afterSend; + _failBeforeSend = beforeSend; + _failOnce = failOnce; + _txBatchSize = txBatchSize; + _isPubSub = pubsub; } /** - * Starts a ping-pong loop running from the command line. The bounce back client {@link org.apache.qpid.requestreply.PingPongBouncer} also needs + * Starts a ping-pong loop running from the command line. The bounce back client {@link PingPongBouncer} also needs * to be started to bounce the pings back again. - *

    - *

    The command line takes from 2 to 4 arguments: - *

    - *
    brokerDetails The broker connection string. - *
    virtualPath The virtual path. - *
    transacted A boolean flag, telling this client whether or not to use transactions. - *
    size The size of ping messages to use, in bytes. - *
    - * - * @param args The command line arguments as defined above. + * + * @param args The command line arguments. */ public static void main(String[] args) throws Exception { @@ -373,21 +382,21 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, String brokerDetails = config.getHost() + ":" + config.getPort(); String virtualpath = "/test"; - String selector = config.getSelector(); + String selector = (config.getSelector() == null) ? DEFAULT_SELECTOR : config.getSelector(); boolean verbose = true; boolean transacted = config.isTransacted(); boolean persistent = config.usePersistentMessages(); int messageSize = (config.getPayload() != 0) ? config.getPayload() : DEFAULT_MESSAGE_SIZE; //int messageCount = config.getMessages(); int destCount = (config.getDestinationsCount() != 0) ? config.getDestinationsCount() : DEFAULT_DESTINATION_COUNT; - int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : DEFAULT_BATCH_SIZE; + int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : DEFAULT_TX_BATCH_SIZE; int rate = (config.getRate() != 0) ? config.getRate() : DEFAULT_RATE; boolean pubsub = config.isPubSub(); String destName = config.getDestination(); if (destName == null) { - destName = PING_DESTINATION_NAME; + destName = DEFAULT_PING_DESTINATION_NAME; } boolean afterCommit = false; @@ -429,15 +438,13 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } // Create a ping producer to handle the request/wait/reply cycle. - PingPongProducer pingProducer = new PingPongProducer(brokerDetails, "guest", "guest", virtualpath, - destName, selector, transacted, persistent, messageSize, verbose, - afterCommit, beforeCommit, afterSend, beforeSend, failOnce, batchSize, - destCount, rate, pubsub); + PingPongProducer pingProducer = + new PingPongProducer(brokerDetails, DEFAULT_USERNAME, DEFAULT_PASSWORD, virtualpath, destName, selector, + transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, + beforeSend, failOnce, batchSize, destCount, rate, pubsub); pingProducer.getConnection().start(); - // Run a few priming pings to remove warm up time from test results. - //pingProducer.prime(PRIMING_LOOPS); // Create a shutdown hook to terminate the ping-pong producer. Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); @@ -450,50 +457,107 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, pingThread.join(); } - private static void usage() + /** + * Convenience method for a short pause. + * + * @param sleepTime The time in milliseconds to pause for. + */ + public static void pause(long sleepTime) { - System.err.println("Usage: TestPingPublisher \n" + "-host : broker host" + "-port : broker port" + - "-destinationname : queue/topic name\n" + - "-transacted : (true/false). Default is false\n" + - "-persistent : (true/false). Default is false\n" + - "-pubsub : (true/false). Default is false\n" + - "-selector : selector string\n" + - "-payload : paylaod size. Default is 0\n" + - //"-messages : no of messages to be sent (if 0, the ping loop will run indefinitely)\n" + - "-destinationscount : no of destinations for multi-destinations test\n" + - "-batchsize : batch size\n" + - "-rate : thruput rate\n"); + if (sleepTime > 0) + { + try + { + Thread.sleep(sleepTime); + } + catch (InterruptedException ie) + { } + } } /** - * Primes the test loop by sending a few messages, then introduces a short wait. This allows the bounce back client - * on the other end a chance to configure its reply producer on the reply to destination. It is also worth calling - * this a few times, in order to prime the JVMs JIT compilation. + * Gets all the reply destinations (to listen for replies on). In this case this will just be the single reply + * to destination of this pinger. * - * @param x The number of priming loops to run. - * @throws JMSException All underlying exceptions are allowed to fall through. + * @return The single reply to destination of this pinger, wrapped in a list. */ - public void prime(int x) throws JMSException + public List getReplyDestinations() { - for (int i = 0; i < x; i++) + _logger.debug("public List getReplyDestinations(): called"); + + List replyDestinations = new ArrayList(); + replyDestinations.add(_replyDestination); + + return replyDestinations; + } + + /** + * Creates the producer to send the pings on. This is created without a default destination. Its persistent delivery + * flag is set accoring the ping producer creation options. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + public void createProducer() throws JMSException + { + _logger.debug("public void createProducer(): called"); + + _producer = (MessageProducer) _producerSession.createProducer(null); + //_producer.setDisableMessageTimestamp(true); + _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + } + + /** + * Creates consumers for the specified number of destinations. The destinations themselves are also created by + * this method. + * + * @param noOfDestinations The number of destinations to create consumers for. + * @param selector The message selector to filter the consumers with. + * @param rootName The root of the name, or actual name if only one is being created. + * @param unique true to make the destinations unique to this pinger, false to share + * the numbering with all pingers on the same JVM. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique) + throws JMSException + { + _logger.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + + ", String selector = " + selector + ", String rootName = " + rootName + ", boolean unique = " + + unique + "): called"); + + // Create the desired number of ping destinations and consumers for them. + for (int i = 0; i < noOfDestinations; i++) { - // Create and send a small message. - Message first = getTestMessage(_replyDestination, 0, false); - sendMessage(first); + AMQDestination destination = null; - commitTx(); + int id; - try + // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag. + if (unique) { - Thread.sleep(100); + id = _queueJVMSequenceID.incrementAndGet(); } - catch (InterruptedException ignore) + else { - + id = _queueSharedId.incrementAndGet(); } - } + // Check if this is a pub/sub pinger, in which case create topics. + if (_isPubSub) + { + AMQShortString name = new AMQShortString(rootName + id); + destination = new AMQTopic(name); + } + // Otherwise this is a p2p pinger, in which case create queues. + else + { + AMQShortString name = new AMQShortString(rootName + id); + destination = new AMQQueue(name, name, false, false, false); + } + // Keep the destination. + _pingDestinations.add(destination); + } } /** @@ -505,52 +569,64 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, */ public void onMessage(Message message) { + _logger.debug("public void onMessage(Message message): called"); try { - - // Store the reply, if it has a correlation id that is expected. + // Extract the messages correlation id. String correlationID = message.getJMSCorrelationID(); + _logger.debug("correlationID = " + correlationID); - if (_verbose) - { - _logger.info(timestampFormatter.format(new Date()) + ": Got reply with correlation id, " + correlationID); - //_logger.debug("Received from : " + message.getJMSDestination()); - } - - // Turn the traffic light to green. + // Countdown on the traffic light if there is one for the matching correlation id. CountDownLatch trafficLight = trafficLights.get(correlationID); if (trafficLight != null) { - if (_messageListener != null) - { - synchronized (trafficLight) - { - _messageListener.onMessage(message); - trafficLight.countDown(); - } - } - else + _logger.debug("Reply was expected, decrementing the latch for the id, " + correlationID); + + // Decrement the countdown latch. Before this point, it is possible that two threads might enter this + // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block + // ensures that each thread will get a unique value for the remaining messages. + long trueCount = -1; + long remainingCount = -1; + + synchronized (trafficLight) { trafficLight.countDown(); - } - _logger.trace("Reply was expected, decrementing the latch for the id."); + trueCount = trafficLight.getCount(); + remainingCount = trueCount - 1; - long remainingCount = trafficLight.getCount(); + _logger.debug("remainingCount = " + remainingCount); + _logger.debug("trueCount = " + trueCount); - if ((remainingCount % _txBatchSize) == 0) - { - commitTx(getConsumerSession()); - } + // Commit on transaction batch size boundaries. At this point in time the waiting producer remains + // blocked, even on the last message. + if ((remainingCount % _txBatchSize) == 0) + { + commitTx(_consumerSession); + } + // Forward the message and remaining count to any interested chained message listener. + if (_chainedMessageListener != null) + { + _chainedMessageListener.onMessage(message, (int) remainingCount); + } + + // Check if this is the last message, in which case release any waiting producers. This is done + // after the transaction has been committed and any listeners notified. + if (trueCount == 1) + { + trafficLight.countDown(); + } + } } else { - _logger.trace("There was no thread waiting for reply: " + correlationID); + _logger.debug("There was no thread waiting for reply: " + correlationID); } + // Print out ping times for every message in verbose mode only. if (_verbose) { Long timestamp = message.getLongProperty("timestamp"); @@ -566,32 +642,70 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, { _logger.warn("There was a JMSException: " + e.getMessage(), e); } + + _logger.debug("public void onMessage(Message message): ending"); } /** * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out - * before a reply arrives, then a null reply is returned from this method. + * before a reply arrives, then a null reply is returned from this method. This method generates a new unqiue + * correlation id for the messages. * * @param message The message to send. * @param numPings The number of ping messages to send. * @param timeout The timeout in milliseconds. + * * @return The number of replies received. This may be less than the number sent if the timeout terminated the * wait for all prematurely. + * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ public int pingAndWaitForReply(Message message, int numPings, long timeout) throws JMSException, InterruptedException { - String messageCorrelationId = null; + _logger.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + + timeout + "): called"); + + // Create a unique correlation id to put on the messages before sending them. + String messageCorrelationId = Long.toString(idGenerator.incrementAndGet()); + + return pingAndWaitForReply(message, numPings, timeout, messageCorrelationId); + } + + /** + * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out + * before a reply arrives, then a null reply is returned from this method. This method allows the caller to specify + * the correlation id. + * + * @param message The message to send. + * @param numPings The number of ping messages to send. + * @param timeout The timeout in milliseconds. + * @param messageCorrelationId The message correlation id. + * + * @return The number of replies received. This may be less than the number sent if the timeout terminated the + * wait for all prematurely. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + */ + public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) + throws JMSException, InterruptedException + { + _logger.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called"); try { - // Put a unique correlation id on the message before sending it. - messageCorrelationId = Long.toString(getNewID()); - + // Create a count down latch to count the number of replies with. This is created before the messages are + // sent so that the replies cannot be received before the count down is created. + // One is added to this, so that the last reply becomes a special case. The special case is that the + // chained message listener must be called before this sender can be unblocked, but that decrementing the + // countdown needs to be done before the chained listener can be called. + CountDownLatch trafficLight = new CountDownLatch(numPings + 1); + trafficLights.put(messageCorrelationId, trafficLight); + + // Send the specifed number of messages. pingNoWaitForReply(message, numPings, messageCorrelationId); - CountDownLatch trafficLight = trafficLights.get(messageCorrelationId); - // Block the current thread until a reply to the message is received, or it times out. + // Block the current thread until replies to all the message are received, or it times out. trafficLight.await(timeout, TimeUnit.MILLISECONDS); // Work out how many replies were receieved. @@ -606,45 +720,37 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, _logger.info("Got all replies on id, " + messageCorrelationId); } - commitTx(getConsumerSession()); + commitTx(_consumerSession); + + _logger.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); return numReplies; } + // Ensure that the message countdown latch is always removed from the reply map. The reply map is long lived, + // so will be a memory leak if this is not done. finally { - removeLock(messageCorrelationId); + trafficLights.remove(messageCorrelationId); } } - public long getNewID() - { - return idGenerator.incrementAndGet(); - } - - public CountDownLatch removeLock(String correlationID) - { - return trafficLights.remove(correlationID); - } - - - /* - * Sends the specified ping message but does not wait for a correlating reply. - * - * @param message The message to send. - * @param numPings The number of pings to send. - * @return The reply, or null if no reply arrives before the timeout. - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - */ - public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException, InterruptedException + /** + * Sends the specified number of ping messages and does not wait for correlating replies. + * + * @param message The message to send. + * @param numPings The number of pings to send. + * @param messageCorrelationId A correlation id to place on all messages sent. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + */ + public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException { - // Create a count down latch to count the number of replies with. This is created before the message is sent - // so that the message is not received before the count down is created. - CountDownLatch trafficLight = new CountDownLatch(numPings); - trafficLights.put(messageCorrelationId, trafficLight); + _logger.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings + + ", String messageCorrelationId = " + messageCorrelationId + "): called"); message.setJMSCorrelationID(messageCorrelationId); - // Set up a committed flag to detect uncommitted message at the end of the send loop. This may occurr if the + // Set up a committed flag to detect uncommitted messages at the end of the send loop. This may occurr if the // transaction batch size is not a factor of the number of pings. In which case an extra commit at the end is // needed. boolean committed = false; @@ -652,55 +758,46 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, // Send all of the ping messages. for (int i = 0; i < numPings; i++) { - // Reset the committed flag to indicate that there are uncommitted message. + // Reset the committed flag to indicate that there are uncommitted messages. committed = false; // Re-timestamp the message. message.setLongProperty("timestamp", System.currentTimeMillis()); - // Check if the test is with multiple-destinations, in which case round robin the destinations - // as the messages are sent. - if (getDestinationsCount() > DEFAULT_DESTINATION_COUNT) - { - sendMessage(getDestination(i % getDestinationsCount()), message); - } - else - { - sendMessage(message); - } + // Round robin the destinations as the messages are sent. + //return _destinationCount; + sendMessage(_pingDestinations.get(i % _pingDestinations.size()), message); - // Apply message rate throttling if a rate limit has been set up and the throttling batch limit has been - // reached. See the comment on the throttle batch size for information about the use of batches here. - if ((rateLimiter != null) && ((i % _throttleBatchSize) == 0)) + // Apply message rate throttling if a rate limit has been set up. + if (_rateLimiter != null) { - rateLimiter.throttle(); + _rateLimiter.throttle(); } // Call commit every time the commit batch size is reached. if ((i % _txBatchSize) == 0) { - commitTx(); + commitTx(_producerSession); committed = true; } + + // Spew out per message timings on every message sonly in verbose mode. + if (_verbose) + { + _logger.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + + messageCorrelationId); + } } // Call commit if the send loop finished before reaching a batch size boundary so there may still be uncommitted messages. if (!committed) { - commitTx(); - } - - // Spew out per message timings only in verbose mode. - if (_verbose) - { - _logger.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); + commitTx(_producerSession); } - } /** - * The ping loop implementation. This send out pings of the configured size, persistence and transactionality, and - * waits for replies and inserts short pauses in between each. + * The ping loop implementation. This sends out pings waits for replies and inserts short pauses in between each. */ public void pingLoop() { @@ -711,10 +808,10 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, msg.setLongProperty("timestamp", System.currentTimeMillis()); // Send the message and wait for a reply. - pingAndWaitForReply(msg, DEFAULT_BATCH_SIZE, TIMEOUT); + pingAndWaitForReply(msg, DEFAULT_TX_BATCH_SIZE, DEFAULT_TIMEOUT); // Introduce a short pause if desired. - pause(SLEEP_TIME); + pause(DEFAULT_SLEEP_TIME); } catch (JMSException e) { @@ -728,79 +825,299 @@ public class PingPongProducer extends AbstractPingProducer implements Runnable, } } - public Destination getReplyDestination() + /*public Destination getReplyDestination() { return _replyDestination; + }*/ + + /** + * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set + * here. + * + * @param messageListener The chained message listener. + */ + public void setChainedMessageListener(ChainedMessageListener messageListener) + { + _chainedMessageListener = messageListener; } - protected void setReplyDestination(Destination destination) + /** + * Removes any chained message listeners from this pinger. + */ + public void removeChainedMessageListener() { - _replyDestination = destination; + _chainedMessageListener = null; } - public void setMessageListener(MessageListener messageListener) + /** + * Generates a test message of the specified size, with the specified reply-to destination and persistence flag. + * + * @param replyQueue The reply-to destination for the message. + * @param messageSize The desired size of the message in bytes. + * @param persistent true if the message should use persistent delivery, false otherwise. + * + * @return A freshly generated test message. + * + * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. + */ + public ObjectMessage getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException { - _messageListener = messageListener; + ObjectMessage msg = TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); + // Timestamp the message. + //msg.setLongProperty("timestamp", System.currentTimeMillis()); + + return msg; } - public CountDownLatch getEndLock(String correlationID) + /** + * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this + * flag has been cleared. + */ + public void stop() { - return trafficLights.get(correlationID); + _publish = false; } - /* - * When the test is being performed with multiple queues, then this method will be used, which has a loop to - * pick up the next queue from the queues list and sends message to it. - * - * @param message - * @param numPings - * @throws JMSException - */ - /*private void pingMultipleQueues(Message message, int numPings) throws JMSException + /** + * Implements a ping loop that repeatedly pings until the publish flag becomes false. + */ + public void run() { - int queueIndex = 0; - for (int i = 0; i < numPings; i++) + // Keep running until the publish flag is cleared. + while (_publish) { - // Re-timestamp the message. - message.setLongProperty("timestamp", System.currentTimeMillis()); + pingLoop(); + } + } - sendMessage(getDestination(queueIndex++), message); + /** + * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the + * connection, this clears the publish flag which in turn will halt the ping loop. + * + * @param e The exception that triggered this callback method. + */ + public void onException(JMSException e) + { + _publish = false; + _logger.debug("There was a JMSException: " + e.getMessage(), e); + } - // reset the counter to get the first queue - if (queueIndex == (getDestinationsCount() - 1)) + /** + * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered + * with the runtime system as a shutdown hook. + * + * @return A shutdown hook for the ping loop. + */ + public Thread getShutdownHook() + { + return new Thread(new Runnable() { - queueIndex = 0; - } + public void run() + { + stop(); + } + }); + } + + /** + * Gets the underlying connection that this ping client is running on. + * + * @return The underlying connection that this ping client is running on. + */ + public Connection getConnection() + { + return _connection; + } + + /** + * Creates consumers for the specified destinations and registers this pinger to listen to their messages. + * + * @param destinations The destinations to listen to. + * @param selector A selector to filter the messages with. + * + * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through. + */ + public void createReplyConsumers(Collection destinations, String selector) throws JMSException + { + _logger.debug("public void createReplyConsumers(Collection destinations = " + destinations + + ", String selector = " + selector + "): called"); + + for (Destination destination : destinations) + { + // Create a consumer for the destination and set this pinger to listen to its messages. + MessageConsumer consumer = + _consumerSession.createConsumer(destination, DEFAULT_PREFETCH, DEFAULT_NO_LOCAL, DEFAULT_EXCLUSIVE, + selector); + consumer.setMessageListener(this); } - }*/ + } /** - * A connection listener that logs out any failover complete events. Could do more interesting things with this - * at some point... + * Closes the pingers connection. + * + * @throws JMSException All JMSException are allowed to fall through. */ - public static class FailoverNotifier implements ConnectionListener + public void close() throws JMSException { - public void bytesSent(long count) + _logger.debug("public void close(): called"); + + if (_connection != null) { + _connection.close(); } + } + + /** + * Convenience method to commit the transaction on the specified session. If the session to commit on is not + * a transactional session, this method does nothing (unless the failover after send flag is set). + * + *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit + * is applied. This flag applies whether the pinger is transactional or not. + * + *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the + * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker + * after the commit is applied. These flags will only apply if using a transactional pinger. + * + * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + * + * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit + * method, because commits only apply to transactional pingers, but fail after send applied to transactional + * and non-transactional alike. + */ + protected void commitTx(Session session) throws JMSException + { + _logger.debug("protected void commitTx(Session session): called"); - public void bytesReceived(long count) + _logger.trace("Batch time reached"); + if (_failAfterSend) { + _logger.trace("Batch size reached"); + if (_failOnce) + { + _failAfterSend = false; + } + + _logger.trace("Failing After Send"); + doFailover(); } - public boolean preFailover(boolean redirect) + if (session.getTransacted()) { - return true; //Allow failover + try + { + if (_failBeforeCommit) + { + if (_failOnce) + { + _failBeforeCommit = false; + } + + _logger.trace("Failing Before Commit"); + doFailover(); + } + + session.commit(); + + if (_failAfterCommit) + { + if (_failOnce) + { + _failAfterCommit = false; + } + + _logger.trace("Failing After Commit"); + doFailover(); + } + + _logger.trace("Session Commited."); + } + catch (JMSException e) + { + _logger.trace("JMSException on commit:" + e.getMessage(), e); + + // Warn that the bounce back client is not available. + if (e.getLinkedException() instanceof AMQNoConsumersException) + { + _logger.debug("No consumers on queue."); + } + + try + { + session.rollback(); + _logger.trace("Message rolled back."); + } + catch (JMSException jmse) + { + _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); + + // Both commit and rollback failed. Throw the rollback exception. + throw jmse; + } + } } + } - public boolean preResubscribe() + /** + * Sends the message to the specified destination. If the destination is null, it gets sent to the default destination + * of the ping producer. If an explicit destination is set, this overrides the default. + * + * @param destination The destination to send to. + * @param message The message to send. + * + * @throws javax.jms.JMSException All underlying JMSExceptions are allowed to fall through. + */ + protected void sendMessage(Destination destination, Message message) throws JMSException + { + if (_failBeforeSend) { - return true; // Allow resubscription + if (_failOnce) + { + _failBeforeSend = false; + } + + _logger.trace("Failing Before Send"); + doFailover(); } - public void failoverComplete() + if (destination == null) + { + _producer.send(message); + } + else { - _logger.info("App got failover complete callback."); + _producer.send(destination, message); } } + + /** + * Prompts the user to terminate the broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + */ + protected void doFailover() + { + System.out.println("Kill Broker now then press return"); + try + { + System.in.read(); + } + catch (IOException e) + { } + + System.out.println("Continuing."); + } + + /** + * Defines a chained message listener interface that can be attached to this pinger. Whenever this pinger's + * {@link PingPongProducer#onMessage} method is called, the chained listener set through the + * {@link PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected + * count of messages with that correlation id. + * + * Provided only one pinger is producing messages with that correlation id, the chained listener will always be + * given unique message counts. It will always be called while the producer waiting for all messages to arrive is + * still blocked. + */ + public static interface ChainedMessageListener + { + public void onMessage(Message message, int remainingCount) throws JMSException; + } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java deleted file mode 100644 index bab732e2a6..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceProvidingClient.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * - * 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.qpid.requestreply; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.jms.ConnectionListener; -import org.apache.qpid.jms.Session; -import org.apache.qpid.url.URLSyntaxException; - -import javax.jms.*; -import java.net.InetAddress; -import java.net.UnknownHostException; - -public class ServiceProvidingClient -{ - private static final Logger _logger = Logger.getLogger(ServiceProvidingClient.class); - - private MessageProducer _destinationProducer; - - private Destination _responseDest; - - private AMQConnection _connection; - - private Session _session; - private Session _producerSession; - - private boolean _isTransactional; - - public ServiceProvidingClient(String brokerDetails, String username, String password, - String clientName, String virtualPath, String serviceName, - final int deliveryMode, boolean transactedMode, String selector) - throws AMQException, JMSException, URLSyntaxException - { - _isTransactional = transactedMode; - - _logger.info("Delivery Mode: " + (deliveryMode == DeliveryMode.NON_PERSISTENT ? "Non Persistent" : "Persistent") - + "\t isTransactional: " + _isTransactional); - - _connection = new AMQConnection(brokerDetails, username, password, clientName, virtualPath); - _connection.setConnectionListener(new ConnectionListener() - { - - public void bytesSent(long count) - { - } - - public void bytesReceived(long count) - { - } - - public boolean preFailover(boolean redirect) - { - return true; - } - - public boolean preResubscribe() - { - return true; - } - - public void failoverComplete() - { - _logger.info("App got failover complete callback"); - } - }); - _session = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE); - _producerSession = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE); - - _logger.info("Service (queue) name is '" + serviceName + "'..."); - - AMQQueue destination = new AMQQueue(serviceName); - - MessageConsumer consumer = _session.createConsumer(destination, - 100, true, false, selector); - - consumer.setMessageListener(new MessageListener() - { - private int _messageCount; - - public void onMessage(Message message) - { - //_logger.info("Got message '" + message + "'"); - TextMessage tm = (TextMessage) message; - try - { - Destination responseDest = tm.getJMSReplyTo(); - if (responseDest == null) - { - _logger.info("Producer not created because the response destination is null."); - return; - } - - if (!responseDest.equals(_responseDest)) - { - _responseDest = responseDest; - - _logger.info("About to create a producer"); - _destinationProducer = _producerSession.createProducer(responseDest); - _destinationProducer.setDisableMessageTimestamp(true); - _destinationProducer.setDeliveryMode(deliveryMode); - _logger.info("After create a producer"); - } - } - catch (JMSException e) - { - _logger.error("Error creating destination"); - } - _messageCount++; - if (_messageCount % 1000 == 0) - { - _logger.info("Received message total: " + _messageCount); - _logger.info("Sending response to '" + _responseDest + "'"); - } - - try - { - String payload = "This is a response: sing together: 'Mahnah mahnah...'" + tm.getText(); - TextMessage msg = _producerSession.createTextMessage(payload); - if (tm.propertyExists("timeSent")) - { - _logger.info("timeSent property set on message"); - long timesent = tm.getLongProperty("timeSent"); - _logger.info("timeSent value is: " + timesent); - msg.setLongProperty("timeSent", timesent); - } - - _destinationProducer.send(msg); - - if (_isTransactional) - { - _producerSession.commit(); - } - if (_isTransactional) - { - _session.commit(); - } - if (_messageCount % 1000 == 0) - { - _logger.info("Sent response to '" + _responseDest + "'"); - } - } - catch (JMSException e) - { - _logger.error("Error sending message: " + e, e); - } - } - }); - } - - public void run() throws JMSException - { - _connection.start(); - _logger.info("Waiting..."); - } - - public static void main(String[] args) - { - _logger.info("Starting..."); - - if (args.length < 5) - { - System.out.println("Usage: serviceProvidingClient [ ] [selector]"); - System.exit(1); - } - String clientId = null; - try - { - InetAddress address = InetAddress.getLocalHost(); - clientId = address.getHostName() + System.currentTimeMillis(); - } - catch (UnknownHostException e) - { - _logger.error("Error: " + e, e); - } - - int deliveryMode = DeliveryMode.NON_PERSISTENT; - boolean transactedMode = false; - - if (args.length > 7) - { - deliveryMode = args[args.length - 2].toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT - : DeliveryMode.NON_PERSISTENT; - - transactedMode = args[args.length - 1].toUpperCase().charAt(0) == 'T' ? true : false; - } - - String selector = null; - if ((args.length == 8) || (args.length == 7)) - { - selector = args[args.length - 1]; - } - - try - { - ServiceProvidingClient client = new ServiceProvidingClient(args[0], args[1], args[2], - clientId, args[3], args[4], - deliveryMode, transactedMode, selector); - client.run(); - } - catch (JMSException e) - { - _logger.error("Error: " + e, e); - } - catch (AMQException e) - { - _logger.error("Error: " + e, e); - } - catch (URLSyntaxException e) - { - _logger.error("Error: " + e, e); - } - } -} - diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java deleted file mode 100644 index 57512929c1..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/ServiceRequestingClient.java +++ /dev/null @@ -1,428 +0,0 @@ -/* - * - * 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.qpid.requestreply; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.message.TestMessageFactory; -import org.apache.qpid.client.message.JMSTextMessage; -import org.apache.qpid.jms.MessageConsumer; -import org.apache.qpid.jms.MessageProducer; -import org.apache.qpid.jms.Session; -import org.apache.qpid.url.URLSyntaxException; - -import javax.jms.*; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * A client that behaves as follows: - *

    • Connects to a queue, whose name is specified as a cmd-line argument
    • - *
    • Creates a temporary queue
    • - *
    • Creates messages containing a property(reply-to) that is the name of the temporary queue
    • - *
    • Fires off a message on the original queue and registers the callbackHandler to listen to the response on the temporary queue
    • - *
    • Start the loop to send all messages
    • - *
    • CallbackHandler keeps listening to the responses and exits if all the messages have been received back or - * if the waiting time for next message is elapsed
    • - *
    - */ -public class ServiceRequestingClient implements ExceptionListener -{ - private static final Logger _log = Logger.getLogger(ServiceRequestingClient.class); - - private long _messageIdentifier = 0; - - // time for which callbackHandler should wait for a message before exiting. Default time= 60 secs - private static long _callbackHandlerWaitingTime = 60000; - - private String MESSAGE_DATA; - - private AMQConnection _connection; - - private Session _session; - private Session _producerSession; - - private long _averageLatency; - - private int _messageCount; - private boolean _isTransactional; - - private volatile boolean _completed; - - private AMQDestination _tempDestination; - - private MessageProducer _producer; - - private Object _waiter; - - private class CallbackHandler implements MessageListener - { - private int _actualMessageCount; - - private long _startTime; - // The time when the last message was received by the callbackHandler - private long _messageReceivedTime = 0; - private Object _timerCallbackHandler = new Object(); - - public CallbackHandler(long startTime) - { - _startTime = startTime; - // Start the timer thread, which will keep checking if test should exit because the waiting time has elapsed - (new Thread(new TimerThread())).start(); - } - - public void onMessage(Message m) - { - _messageReceivedTime = System.currentTimeMillis(); - if (_log.isDebugEnabled()) - { - _log.debug("Message received: " + m); - } - try - { - m.getPropertyNames(); - if (m.propertyExists("timeSent")) - { - long timeSent = m.getLongProperty("timeSent"); - if (_averageLatency == 0) - { - _averageLatency = _messageReceivedTime - timeSent; - _log.info("Latency " + _averageLatency); - } - else - { - _log.info("Individual latency: " + (_messageReceivedTime - timeSent)); - _averageLatency = (_averageLatency + (_messageReceivedTime - timeSent)) / 2; - _log.info("Average latency now: " + _averageLatency); - } - } - if(_isTransactional) - { - _session.commit(); - } - } - catch (JMSException e) - { - _log.error("Error getting latency data: " + e, e); - } - _actualMessageCount++; - if (_actualMessageCount % 1000 == 0) - { - _log.info("Received message count: " + _actualMessageCount); - } - - checkForMessageID(m); - - if (_actualMessageCount == _messageCount) - { - finishTesting(_actualMessageCount); - } - } - - /** - * sets completed flag to true, closes the callbackHandler connection and notifies the waiter thread, - * so that the callbackHandler can finish listening for messages. This causes the test to finish. - * @param receivedMessageCount - */ - private void finishTesting(int receivedMessageCount) - { - _completed = true; - notifyWaiter(); - notifyTimerThread(); - - long timeTaken = System.currentTimeMillis() - _startTime; - _log.info("***** Result *****"); - _log.info("Total messages received = " + receivedMessageCount); - _log.info("Total time taken to receive " + receivedMessageCount + " messages was " + - timeTaken + "ms, equivalent to " + - (receivedMessageCount / (timeTaken / 1000.0)) + " messages per second"); - - try - { - _connection.close(); - _log.info("Connection closed"); - } - catch (JMSException e) - { - _log.error("Error closing connection"); - } - } - - private void notifyTimerThread() - { - if (_timerCallbackHandler != null) - { - synchronized (_timerCallbackHandler) - { - _timerCallbackHandler.notify(); - } - } - } - - /** - * Thread class implementing the timer for callbackHandler. The thread will exit the test if the waiting time - * has elapsed before next message is received. - */ - private class TimerThread implements Runnable - { - public void run() - { - do - { - try - { - synchronized(_timerCallbackHandler) - { - _timerCallbackHandler.wait(_callbackHandlerWaitingTime); - } - } - catch (InterruptedException ignore) - { - - } - - // exit if callbackHandler has received all messages - if (_completed) - { - return; - } - } - while ((System.currentTimeMillis() - _messageReceivedTime) < _callbackHandlerWaitingTime); - - // waiting time has elapsed, so exit the test - _log.info(""); - _log.info("Exited after waiting for " + _callbackHandlerWaitingTime/1000 + " secs"); - finishTesting(_actualMessageCount); - } - } - } // end of CallbackHandler class - - /** - * Checks if the received AMQ Message ID(delivery tag) is in sequence, by comparing it with the AMQ MessageID - * of previous message. - * @param receivedMsg - */ - private void checkForMessageID(Message receivedMsg) - { - try - { - JMSTextMessage msg = (JMSTextMessage)receivedMsg; - if (! (msg.getDeliveryTag() == _messageIdentifier + 1)) - { - _log.info("Out of sequence message received. Previous AMQ MessageID= " + _messageIdentifier + - ", Received AMQ messageID= " + receivedMsg.getJMSMessageID()); - } - _messageIdentifier = msg.getDeliveryTag(); - } - catch (Exception ex) - { - _log.error("Error in checking messageID ", ex); - } - - } - - private void notifyWaiter() - { - if (_waiter != null) - { - synchronized (_waiter) - { - _waiter.notify(); - } - } - } - - public ServiceRequestingClient(String brokerHosts, String clientID, String username, String password, - String vpath, String commandQueueName, - int deliveryMode, boolean transactedMode, - final int messageCount, final int messageDataLength) throws AMQException, URLSyntaxException - { - _isTransactional = transactedMode; - - _log.info("Delivery Mode: " + (deliveryMode == DeliveryMode.NON_PERSISTENT ? "Non Persistent" : "Persistent")); - _log.info("isTransactional: " + _isTransactional); - - _messageCount = messageCount; - MESSAGE_DATA = TestMessageFactory.createMessagePayload(messageDataLength); - try - { - createConnection(brokerHosts, clientID, username, password, vpath); - _session = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE); - _producerSession = (Session) _connection.createSession(_isTransactional, Session.AUTO_ACKNOWLEDGE); - - _connection.setExceptionListener(this); - - AMQQueue destination = new AMQQueue(commandQueueName); - _producer = (MessageProducer) _producerSession.createProducer(destination); - _producer.setDisableMessageTimestamp(true); - _producer.setDeliveryMode(deliveryMode); - - _tempDestination = new AMQQueue("TempResponse" + - Long.toString(System.currentTimeMillis()), true); - MessageConsumer messageConsumer = (MessageConsumer) _session.createConsumer(_tempDestination, 100, true, - true, null); - - //Send first message, then wait a bit to allow the provider to get initialised - TextMessage first = _session.createTextMessage(MESSAGE_DATA); - first.setJMSReplyTo(_tempDestination); - _producer.send(first); - if (_isTransactional) - { - _producerSession.commit(); - } - try - { - Thread.sleep(1000); - } - catch (InterruptedException ignore) - { - } - - //now start the clock and the test... - final long startTime = System.currentTimeMillis(); - - messageConsumer.setMessageListener(new CallbackHandler(startTime)); - } - catch (JMSException e) - { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - } - - /** - * Run the test and notify an object upon receipt of all responses. - * - * @param waiter the object that will be notified - * @throws JMSException - */ - public void run(Object waiter) throws JMSException - { - _waiter = waiter; - _connection.start(); - for (int i = 1; i < _messageCount; i++) - { - TextMessage msg = _producerSession.createTextMessage(MESSAGE_DATA + i); - msg.setJMSReplyTo(_tempDestination); - if (i % 1000 == 0) - { - long timeNow = System.currentTimeMillis(); - msg.setLongProperty("timeSent", timeNow); - } - _producer.send(msg); - if (_isTransactional) - { - _producerSession.commit(); - } - - } - _log.info("Finished sending " + _messageCount + " messages"); - } - - public boolean isCompleted() - { - return _completed; - } - - private void createConnection(String brokerHosts, String clientID, String username, String password, - String vpath) throws AMQException, URLSyntaxException - { - _connection = new AMQConnection(brokerHosts, username, password, clientID, vpath); - } - - /** - * @param args argument 1 if present specifies the name of the temporary queue to create. Leaving it blank - * means the server will allocate a name. - */ - public static void main(String[] args) - { - if ((args.length < 6) || (args.length == 8)) - { - System.err.println("Usage: ServiceRequestingClient " + - " [] " + - "[ ] " + - "[]"); - System.exit(1); - } - try - { - int messageSize = 4096; - boolean transactedMode = false; - int deliveryMode = DeliveryMode.NON_PERSISTENT; - - if (args.length > 6) - { - messageSize = Integer.parseInt(args[6]); - } - if (args.length > 7) - { - deliveryMode = args[7].toUpperCase().charAt(0) == 'P' ? DeliveryMode.PERSISTENT - : DeliveryMode.NON_PERSISTENT; - - transactedMode = args[8].toUpperCase().charAt(0) == 'T' ? true : false; - } - - if (args.length > 9) - { - _callbackHandlerWaitingTime = Long.parseLong(args[9]) * 1000; - } - - _log.info("Each message size = " + messageSize + " bytes"); - - InetAddress address = InetAddress.getLocalHost(); - String clientID = address.getHostName() + System.currentTimeMillis(); - ServiceRequestingClient client = new ServiceRequestingClient(args[0], clientID, args[1], args[2], args[3], - args[4], deliveryMode, transactedMode, Integer.parseInt(args[5]), - messageSize); - Object waiter = new Object(); - client.run(waiter); - - // Start a thread to - synchronized (waiter) - { - while (!client.isCompleted()) - { - waiter.wait(); - } - } - } - catch (UnknownHostException e) - { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - catch (Exception e) - { - System.err.println("Error in client: " + e); - e.printStackTrace(); - } - } - - /** - * @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) - */ - public void onException(JMSException e) - { - System.err.println(e.getMessage()); - e.printStackTrace(System.err); - } -} -- cgit v1.2.1 From 8c5c298fc5d318bfc7a0bf72b6f61b4402c2f493 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Tue, 30 Jan 2007 16:42:37 +0000 Subject: (Submitted by Rupert Smith) Added PingClient.java which was forgotten from last commit. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@501457 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/ping/PingClient.java | 90 ++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java new file mode 100644 index 0000000000..7fd91ca39d --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java @@ -0,0 +1,90 @@ +/* + * + * 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.qpid.ping; + +import java.util.List; + +import javax.jms.Destination; + +import org.apache.qpid.requestreply.PingPongProducer; + +/** + * PingClient is a {@link PingPongProducer} that does not need a {@link org.apache.qpid.requestreply.PingPongBouncer} + * to send replies to its pings. It simply listens to its own ping destinations, rather than seperate reply queues. + * It is an all in one ping client, that produces and consumes its own pings. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Create a ping pong producer that listens to its own pings {@link PingPongProducer} + *
    + */ +public class PingClient extends PingPongProducer +{ + /** + * Creates a ping producer with the specified parameters, of which there are many. See their individual comments + * for details. This constructor creates ping pong producer but de-registers its reply-to destination message + * listener, and replaces it by listening to all of its ping destinations. + * + * @param brokerDetails The URL of the broker to send pings to. + * @param username The username to log onto the broker with. + * @param password The password to log onto the broker with. + * @param virtualpath The virtual host name to use on the broker. + * @param destinationName The name (or root where multiple destinations are used) of the desitination to send + * pings to. + * @param selector The selector to filter replies with. + * @param transacted Indicates whether or not pings are sent and received in transactions. + * @param persistent Indicates whether pings are sent using peristent delivery. + * @param messageSize Specifies the size of ping messages to send. + * @param verbose Indicates that information should be printed to the console on every ping. + * @param afterCommit Indicates that the user should be promted to terminate a broker after commits to test failover. + * @param beforeCommit Indicates that the user should be promted to terminate a broker before commits to test failover. + * @param afterSend Indicates that the user should be promted to terminate a broker after sends to test failover. + * @param beforeSend Indicates that the user should be promted to terminate a broker before sends to test failover. + * @param failOnce Indicates that the failover testing behaviour should only happen on the first commit, not all. + * @param txBatchSize Specifies the number of pings to send in each transaction. + * @param noOfDestinations The number of destinations to ping. Must be 1 or more. + * @param rate Specified the number of pings per second to send. Setting this to 0 means send as fast as + * possible, with no rate restriction. + * @param pubsub + * + * @throws Exception Any exceptions are allowed to fall through. + */ + public PingClient(String brokerDetails, String username, String password, String virtualpath, String destinationName, + String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, + boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, + int txBatchSize, int noOfDestinations, int rate, boolean pubsub) throws Exception + { + super(brokerDetails, username, password, virtualpath, destinationName, selector, transacted, persistent, messageSize, + verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, txBatchSize, noOfDestinations, rate, + pubsub); + } + + /** + * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the + * effect of making this pinger listen to its own pings. + * + * @return The ping destinations. + */ + public List getReplyDestinations() + { + return _pingDestinations; + } +} -- cgit v1.2.1 From 61c8e33910c9ae4336747790c05d1494737a5511 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 31 Jan 2007 11:29:33 +0000 Subject: (Patch submitted by Rupert Smith) Added a ping latency test. Uploaded new junit-toolkit snapshot for self timed tests. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@501804 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/requestreply/PingPongProducer.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 310ec5f5e3..885277c533 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -198,6 +198,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Holds the default verbose mode. */ public static final boolean DEFAULT_VERBOSE = false; + /** Holds the name of the property to store nanosecond timestamps in ping messages with. */ + public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp"; + /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ private static AtomicLong idGenerator = new AtomicLong(0L); @@ -629,12 +632,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Print out ping times for every message in verbose mode only. if (_verbose) { - Long timestamp = message.getLongProperty("timestamp"); + Long timestamp = message.getLongProperty(MESSAGE_TIMESTAMP_PROPNAME); if (timestamp != null) { - long diff = System.currentTimeMillis() - timestamp; - _logger.trace("Time for round trip: " + diff); + long diff = System.nanoTime() - timestamp; + _logger.trace("Time for round trip (nanos): " + diff); } } } @@ -762,7 +765,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis committed = false; // Re-timestamp the message. - message.setLongProperty("timestamp", System.currentTimeMillis()); + message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); // Round robin the destinations as the messages are sent. //return _destinationCount; @@ -805,7 +808,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { // Generate a sample message and time stamp it. ObjectMessage msg = getTestMessage(_replyDestination, _messageSize, _persistent); - msg.setLongProperty("timestamp", System.currentTimeMillis()); + msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); // Send the message and wait for a reply. pingAndWaitForReply(msg, DEFAULT_TX_BATCH_SIZE, DEFAULT_TIMEOUT); @@ -863,8 +866,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public ObjectMessage getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException { ObjectMessage msg = TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); - // Timestamp the message. - //msg.setLongProperty("timestamp", System.currentTimeMillis()); + + // Timestamp the message in nanoseconds. + msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); return msg; } -- cgit v1.2.1 From 61b2ff54f755f7c1fd0392482a4067e1d57681bd Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Thu, 1 Feb 2007 10:01:32 +0000 Subject: virtual host string corrected git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@502178 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java | 2 +- .../src/main/java/org/apache/qpid/requestreply/PingPongProducer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java index 87edd31575..ab795d0459 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -188,7 +188,7 @@ public class PingPongBouncer implements MessageListener Config config = new Config(); config.setOptions(args); String brokerDetails = config.getHost() + ":" + config.getPort(); - String virtualpath = "/test"; + String virtualpath = "test"; String destinationName = config.getDestination(); if (destinationName == null) { diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 885277c533..b5b8408ad3 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -384,7 +384,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } String brokerDetails = config.getHost() + ":" + config.getPort(); - String virtualpath = "/test"; + String virtualpath = "test"; String selector = (config.getSelector() == null) ? DEFAULT_SELECTOR : config.getSelector(); boolean verbose = true; boolean transacted = config.isTransacted(); -- cgit v1.2.1 From 2433bfc0e042cb76578fde6f54b4f88cc208c02c Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 1 Feb 2007 10:13:21 +0000 Subject: (Submitted by Rupert Smith) Added comments as a reminder of improvements to be made to the tests. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@502179 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongProducer.java | 29 +++++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index b5b8408ad3..c212d3a0e7 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -69,9 +69,33 @@ import uk.co.thebadgerset.junit.extensions.Throttle; *

    * * @todo The use of a ping rate {@link #DEFAULT_RATE} and waits between pings {@link #DEFAULT_SLEEP_TIME} are overlapping. - * Use the rate and throttling only. + * Use the rate and throttling only. Ideally, optionally pass the rate throttle into the ping method, throttle to + * be created and configured by the test runner from the -f command line option and made available through + * the timing controller on timing aware tests or by throttling rate of calling tests methods on non-timing aware + * tests. * * @todo Make shared or unique destinations a configurable option, hard coded to false. + * + * @todo Make acknowledege mode a test option. + * + * @todo Make the message listener a static for all replies to be sent to. It won't be any more of a bottle neck than + * having one per PingPongProducer, as will synchronize on message correlation id, allowing threads to process + * messages concurrently for different ids. Needs to be static so that when using a chained message listener and + * shared destinations between multiple PPPs, it gets notified about all replies, not just those that happen to + * be picked up by the PPP that it is atteched to. + * + * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock + * pair. Obtian read lock on all messages, before decrementing the message count. At the end of the on message + * method add a block that obtains the write lock for the very last message, releases any waiting producer. Means + * that the last message waits until all other messages have been handled before releasing producers. + * + * @todo Set the timeout to be per message correlation id. Restart it every time a message is received (with matching id). + * Means that timeout is measuring situations whether a particular ping stream has pasued for too long, rather than + * the time to send an entire block of messages. This will be better because the timeout won't need to be adjusted + * depending on the total number of messages being sent. Logic to be added to sendAndWait to recheck the timeout + * whenever its wait expires. + * + * @todo Need to multiply up the number of expected messages for pubsub tests as each can be received by many consumers? */ public class PingPongProducer implements Runnable, MessageListener, ExceptionListener { @@ -223,9 +247,6 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Destination where the response messages will arrive. */ private Destination _replyDestination; - /** Destination where the producer will be sending message to. */ - //private Destination _pingDestination; - /** Determines whether this producer sends persistent messages. */ protected boolean _persistent; -- cgit v1.2.1 From c1d55b07f5f900f8cc46bb8814da03d1fa00adb6 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 1 Feb 2007 10:18:36 +0000 Subject: (Submitted by Rupert Smith) Added comments as a reminder of improvements to be made to the tests. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@502182 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/requestreply/PingPongProducer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index c212d3a0e7..7c5bb92a57 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -87,7 +87,8 @@ import uk.co.thebadgerset.junit.extensions.Throttle; * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock * pair. Obtian read lock on all messages, before decrementing the message count. At the end of the on message * method add a block that obtains the write lock for the very last message, releases any waiting producer. Means - * that the last message waits until all other messages have been handled before releasing producers. + * that the last message waits until all other messages have been handled before releasing producers but allows + * messages to be processed concurrently, unlike the current synchronized block. * * @todo Set the timeout to be per message correlation id. Restart it every time a message is received (with matching id). * Means that timeout is measuring situations whether a particular ping stream has pasued for too long, rather than -- cgit v1.2.1 From 77b10120d80bc774c55591872c88992acc3caee7 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 2 Feb 2007 11:13:13 +0000 Subject: QPID-343 Performance test suite doesn't output missing message count on failure. Updated PingAsyncTestPerf to output missing messsage count. Updated PingPongProducer so it doesn't use AMQShortStringx. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@502576 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/requestreply/PingPongProducer.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 7c5bb92a57..ce64a40217 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -34,9 +34,13 @@ import javax.jms.*; import org.apache.log4j.Logger; -import org.apache.qpid.client.*; + import org.apache.qpid.client.message.TestMessageFactory; -import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQNoConsumersException; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; import org.apache.qpid.topic.Config; @@ -570,14 +574,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Check if this is a pub/sub pinger, in which case create topics. if (_isPubSub) { - AMQShortString name = new AMQShortString(rootName + id); - destination = new AMQTopic(name); + destination = new AMQTopic(rootName + id); } // Otherwise this is a p2p pinger, in which case create queues. else { - AMQShortString name = new AMQShortString(rootName + id); - destination = new AMQQueue(name, name, false, false, false); + destination = new AMQQueue(rootName + id); } // Keep the destination. -- cgit v1.2.1 From 7c8d1cda8ea5b2680f296c3d3e86dd9d330f5804 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Fri, 2 Feb 2007 15:09:08 +0000 Subject: (Submitted by Rupert Smith) Perftests improved with better timeout handling. Shared/unique destinations to ping now an option. TestRunner now runs all per-thread setups, synchs all threads, then runs tests, synchas all threads, then runs tear downs. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@502620 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/ping/PingClient.java | 7 +- .../apache/qpid/requestreply/PingPongProducer.java | 118 +++++++++++++++------ 2 files changed, 90 insertions(+), 35 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java index 7fd91ca39d..0e3d753fea 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java @@ -63,18 +63,19 @@ public class PingClient extends PingPongProducer * @param noOfDestinations The number of destinations to ping. Must be 1 or more. * @param rate Specified the number of pings per second to send. Setting this to 0 means send as fast as * possible, with no rate restriction. - * @param pubsub + * @param pubsub True to ping topics, false to ping queues. + * @param unique True to use unique destinations for each ping pong producer, false to share. * * @throws Exception Any exceptions are allowed to fall through. */ public PingClient(String brokerDetails, String username, String password, String virtualpath, String destinationName, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, - int txBatchSize, int noOfDestinations, int rate, boolean pubsub) throws Exception + int txBatchSize, int noOfDestinations, int rate, boolean pubsub, boolean unique) throws Exception { super(brokerDetails, username, password, virtualpath, destinationName, selector, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, txBatchSize, noOfDestinations, rate, - pubsub); + pubsub, unique); } /** diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index ce64a40217..75e49d9e36 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -34,13 +34,12 @@ import javax.jms.*; import org.apache.log4j.Logger; - -import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQNoConsumersException; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; import org.apache.qpid.topic.Config; @@ -78,11 +77,9 @@ import uk.co.thebadgerset.junit.extensions.Throttle; * the timing controller on timing aware tests or by throttling rate of calling tests methods on non-timing aware * tests. * - * @todo Make shared or unique destinations a configurable option, hard coded to false. - * * @todo Make acknowledege mode a test option. * - * @todo Make the message listener a static for all replies to be sent to. It won't be any more of a bottle neck than + * @todo Make the message listener a static for all replies to be sent to? It won't be any more of a bottle neck than * having one per PingPongProducer, as will synchronize on message correlation id, allowing threads to process * messages concurrently for different ids. Needs to be static so that when using a chained message listener and * shared destinations between multiple PPPs, it gets notified about all replies, not just those that happen to @@ -94,12 +91,6 @@ import uk.co.thebadgerset.junit.extensions.Throttle; * that the last message waits until all other messages have been handled before releasing producers but allows * messages to be processed concurrently, unlike the current synchronized block. * - * @todo Set the timeout to be per message correlation id. Restart it every time a message is received (with matching id). - * Means that timeout is measuring situations whether a particular ping stream has pasued for too long, rather than - * the time to send an entire block of messages. This will be better because the timeout won't need to be adjusted - * depending on the total number of messages being sent. Logic to be added to sendAndWait to recheck the timeout - * whenever its wait expires. - * * @todo Need to multiply up the number of expected messages for pubsub tests as each can be received by many consumers? */ public class PingPongProducer implements Runnable, MessageListener, ExceptionListener @@ -155,6 +146,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public static final String COMMIT_BATCH_SIZE_PROPNAME = "CommitBatchSize"; + public static final String UNIQUE_PROPNAME = "uniqueDests"; + /** Used to set up a default message size. */ public static final int DEFAULT_MESSAGE_SIZE = 0; @@ -171,7 +164,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public static final long DEFAULT_SLEEP_TIME = 250; /** Default time to wait before assuming that a ping has timed out. */ - public static final long DEFAULT_TIMEOUT = 9000; + public static final long DEFAULT_TIMEOUT = 30000; /** Defines the default number of pings to send in each transaction when running transactionally. */ public static final int DEFAULT_TX_BATCH_SIZE = 100; @@ -227,18 +220,25 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Holds the default verbose mode. */ public static final boolean DEFAULT_VERBOSE = false; + public static final boolean DEFAULT_UNIQUE = true; + /** Holds the name of the property to store nanosecond timestamps in ping messages with. */ public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp"; /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ - private static AtomicLong idGenerator = new AtomicLong(0L); + private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); + + /** A source for providing unique ids to PingPongProducer. */ + private static AtomicInteger _pingProducerIdGenerator; /** * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross * multiple ping producers on the same JVM. */ - private static Map trafficLights = - Collections.synchronizedMap(new HashMap()); + /*private static Map trafficLights = + Collections.synchronizedMap(new HashMap());*/ + private static Map perCorrelationIds = + Collections.synchronizedMap(new HashMap()); /** A convenient formatter to use when time stamping output. */ protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); @@ -337,7 +337,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * @param noOfDestinations The number of destinations to ping. Must be 1 or more. * @param rate Specified the number of pings per second to send. Setting this to 0 means send as fast as * possible, with no rate restriction. - * @param pubsub + * @param pubsub True to ping topics, false to ping queues. + * @param unique True to use unique destinations for each ping pong producer, false to share. * * @throws Exception Any exceptions are allowed to fall through. */ @@ -345,8 +346,18 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis String destinationName, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int txBatchSize, int noOfDestinations, int rate, - boolean pubsub) throws Exception + boolean pubsub, boolean unique) throws Exception { + _logger.debug("public PingPongProducer(String brokerDetails = " + brokerDetails + ", String username = " + username + + ", String password = " + password + ", String virtualpath = " + virtualpath + + ", String destinationName = " + destinationName + ", String selector = " + selector + + ", boolean transacted = " + transacted + ", boolean persistent = " + persistent + + ", int messageSize = " + messageSize + ", boolean verbose = " + verbose + ", boolean afterCommit = " + + afterCommit + ", boolean beforeCommit = " + beforeCommit + ", boolean afterSend = " + afterSend + + ", boolean beforeSend = " + beforeSend + ", boolean failOnce = " + failOnce + ", int txBatchSize = " + + txBatchSize + ", int noOfDestinations = " + noOfDestinations + ", int rate = " + rate + + ", boolean pubsub = " + pubsub + ", boolean unique = " + unique + "): called"); + // Check that one or more destinations were specified. if (noOfDestinations < 1) { @@ -375,7 +386,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Create the producer and the consumers for all reply destinations. createProducer(); - createPingDestinations(noOfDestinations, selector, destinationName, true); + createPingDestinations(noOfDestinations, selector, destinationName, unique); createReplyConsumers(getReplyDestinations(), selector); // Keep all the remaining options. @@ -470,7 +481,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis PingPongProducer pingProducer = new PingPongProducer(brokerDetails, DEFAULT_USERNAME, DEFAULT_PASSWORD, virtualpath, destName, selector, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, - beforeSend, failOnce, batchSize, destCount, rate, pubsub); + beforeSend, failOnce, batchSize, destCount, rate, pubsub, false); pingProducer.getConnection().start(); @@ -605,10 +616,15 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _logger.debug("correlationID = " + correlationID); // Countdown on the traffic light if there is one for the matching correlation id. - CountDownLatch trafficLight = trafficLights.get(correlationID); + PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); - if (trafficLight != null) + if (perCorrelationId != null) { + CountDownLatch trafficLight = perCorrelationId.trafficLight; + + // Restart the timeout timer on every message. + perCorrelationId.timeOutStart = System.nanoTime(); + _logger.debug("Reply was expected, decrementing the latch for the id, " + correlationID); // Decrement the countdown latch. Before this point, it is possible that two threads might enter this @@ -650,7 +666,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } else { - _logger.debug("There was no thread waiting for reply: " + correlationID); + _logger.warn("Got unexpected message with correlationId: " + correlationID); } // Print out ping times for every message in verbose mode only. @@ -693,7 +709,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis + timeout + "): called"); // Create a unique correlation id to put on the messages before sending them. - String messageCorrelationId = Long.toString(idGenerator.incrementAndGet()); + String messageCorrelationId = Long.toString(_correlationIdGenerator.incrementAndGet()); return pingAndWaitForReply(message, numPings, timeout, messageCorrelationId); } @@ -726,17 +742,42 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // One is added to this, so that the last reply becomes a special case. The special case is that the // chained message listener must be called before this sender can be unblocked, but that decrementing the // countdown needs to be done before the chained listener can be called. - CountDownLatch trafficLight = new CountDownLatch(numPings + 1); - trafficLights.put(messageCorrelationId, trafficLight); + PerCorrelationId perCorrelationId = new PerCorrelationId(); + perCorrelationId.trafficLight = new CountDownLatch(numPings + 1); + perCorrelationIds.put(messageCorrelationId, perCorrelationId); + + // Set up the current time as the start time for pinging on the correlation id. This is used to determine + // timeouts. + perCorrelationId.timeOutStart = System.nanoTime(); // Send the specifed number of messages. pingNoWaitForReply(message, numPings, messageCorrelationId); - // Block the current thread until replies to all the message are received, or it times out. - trafficLight.await(timeout, TimeUnit.MILLISECONDS); + boolean timedOut = false; + boolean allMessagesReceived = false; + int numReplies = 0; + + do + { + // Block the current thread until replies to all the messages are received, or it times out. + perCorrelationId.trafficLight.await(timeout, TimeUnit.MILLISECONDS); + + // Work out how many replies were receieved. + numReplies = numPings - (int) perCorrelationId.trafficLight.getCount(); + allMessagesReceived = numReplies >= numPings; + + _logger.debug("numReplies = "+ numReplies); + _logger.debug("allMessagesReceived = "+ allMessagesReceived); + + // Recheck the timeout condition. + long now = System.nanoTime(); + long lastMessageReceievedAt = perCorrelationId.timeOutStart; + timedOut = (now - lastMessageReceievedAt) > (timeout * 1000000); - // Work out how many replies were receieved. - int numReplies = numPings - (int) trafficLight.getCount(); + _logger.debug("now = " + now); + _logger.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); + } + while (!timedOut && !allMessagesReceived); if ((numReplies < numPings) && _verbose) { @@ -757,7 +798,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // so will be a memory leak if this is not done. finally { - trafficLights.remove(messageCorrelationId); + perCorrelationIds.remove(messageCorrelationId); } } @@ -1148,4 +1189,17 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { public void onMessage(Message message, int remainingCount) throws JMSException; } + + /** + * Holds information on each correlation id. The countdown latch, the current timeout timer... More stuff to be + * added to this: read/write lock to make onMessage more concurrent as described in class header comment. + */ + protected static class PerCorrelationId + { + /** Holds a countdown on number of expected messages. */ + CountDownLatch trafficLight; + + /** Holds the last timestamp that the timeout was reset to. */ + Long timeOutStart; + } } -- cgit v1.2.1 From 7a92628379be27305863d89e8e52aae67c9a1797 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Fri, 2 Feb 2007 16:59:14 +0000 Subject: (Submitted by Rupert Smith) Options moved to top of contructor. Were at bottom and not being used! git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@502655 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongProducer.java | 28 ++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 75e49d9e36..c2962e48c9 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -358,6 +358,18 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis + txBatchSize + ", int noOfDestinations = " + noOfDestinations + ", int rate = " + rate + ", boolean pubsub = " + pubsub + ", boolean unique = " + unique + "): called"); + // Keep all the relevant options. + _persistent = persistent; + _messageSize = messageSize; + _verbose = verbose; + _failAfterCommit = afterCommit; + _failBeforeCommit = beforeCommit; + _failAfterSend = afterSend; + _failBeforeSend = beforeSend; + _failOnce = failOnce; + _txBatchSize = txBatchSize; + _isPubSub = pubsub; + // Check that one or more destinations were specified. if (noOfDestinations < 1) { @@ -388,18 +400,6 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis createProducer(); createPingDestinations(noOfDestinations, selector, destinationName, unique); createReplyConsumers(getReplyDestinations(), selector); - - // Keep all the remaining options. - _persistent = persistent; - _messageSize = messageSize; - _verbose = verbose; - _failAfterCommit = afterCommit; - _failBeforeCommit = beforeCommit; - _failAfterSend = afterSend; - _failBeforeSend = beforeSend; - _failOnce = failOnce; - _txBatchSize = txBatchSize; - _isPubSub = pubsub; } /** @@ -575,21 +575,25 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag. if (unique) { + _logger.debug("Creating unique destinations."); id = _queueJVMSequenceID.incrementAndGet(); } else { + _logger.debug("Creating shared destinations."); id = _queueSharedId.incrementAndGet(); } // Check if this is a pub/sub pinger, in which case create topics. if (_isPubSub) { + _logger.debug("Creating topics."); destination = new AMQTopic(rootName + id); } // Otherwise this is a p2p pinger, in which case create queues. else { + _logger.debug("Creating queues."); destination = new AMQQueue(rootName + id); } -- cgit v1.2.1 From 14f4173bd30a2ae86a0bed11837735e87352a9f6 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 5 Feb 2007 09:49:59 +0000 Subject: Update to performance testing to allow the use of shared destinations. This allows topics to have multiple consumers and the total message counts updated correctly. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@503609 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/ping/PingClient.java | 17 + .../apache/qpid/requestreply/PingPongProducer.java | 378 ++++++++++++++------- 2 files changed, 273 insertions(+), 122 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java index 0e3d753fea..1a37f47b35 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java @@ -38,6 +38,8 @@ import org.apache.qpid.requestreply.PingPongProducer; */ public class PingClient extends PingPongProducer { + private static int _pingClientCount; + /** * Creates a ping producer with the specified parameters, of which there are many. See their individual comments * for details. This constructor creates ping pong producer but de-registers its reply-to destination message @@ -76,6 +78,8 @@ public class PingClient extends PingPongProducer super(brokerDetails, username, password, virtualpath, destinationName, selector, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, txBatchSize, noOfDestinations, rate, pubsub, unique); + + _pingClientCount++; } /** @@ -88,4 +92,17 @@ public class PingClient extends PingPongProducer { return _pingDestinations; } + + public int getConsumersPerTopic() + { + if (_isUnique) + { + return 1; + } + else + { + return _pingClientCount; + } + } + } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index c2962e48c9..8def95f7b1 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -50,21 +50,21 @@ import uk.co.thebadgerset.junit.extensions.Throttle; /** * PingPongProducer is a client that sends pings to a queue and waits for pongs to be bounced back by a bounce back * client (see {@link PingPongBouncer} for the bounce back client). - * + *

    *

    The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. * This means that this class has to do some work to correlate pings with pongs; it expectes the original message * correlation id in the ping to be bounced back in the reply correlation id. - * + *

    *

    This ping tool accepts a vast number of configuration options, all of which are passed in to the constructor. * It can ping topics or queues; ping multiple destinations; do persistent pings; send messages of any size; do pings * within transactions; control the number of pings to send in each transaction; limit its sending rate; and perform * failover testing. - * + *

    *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so * by starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is * also registered to terminate the ping-pong loop cleanly. - * + *

    *

    *
    CRC Card
    Responsibilities Collaborations *
    Provide a ping and wait for all responses cycle. @@ -72,55 +72,67 @@ import uk.co.thebadgerset.junit.extensions.Throttle; *
    * * @todo The use of a ping rate {@link #DEFAULT_RATE} and waits between pings {@link #DEFAULT_SLEEP_TIME} are overlapping. - * Use the rate and throttling only. Ideally, optionally pass the rate throttle into the ping method, throttle to - * be created and configured by the test runner from the -f command line option and made available through - * the timing controller on timing aware tests or by throttling rate of calling tests methods on non-timing aware - * tests. - * + * Use the rate and throttling only. Ideally, optionally pass the rate throttle into the ping method, throttle to + * be created and configured by the test runner from the -f command line option and made available through + * the timing controller on timing aware tests or by throttling rate of calling tests methods on non-timing aware + * tests. * @todo Make acknowledege mode a test option. - * * @todo Make the message listener a static for all replies to be sent to? It won't be any more of a bottle neck than - * having one per PingPongProducer, as will synchronize on message correlation id, allowing threads to process - * messages concurrently for different ids. Needs to be static so that when using a chained message listener and - * shared destinations between multiple PPPs, it gets notified about all replies, not just those that happen to - * be picked up by the PPP that it is atteched to. - * + * having one per PingPongProducer, as will synchronize on message correlation id, allowing threads to process + * messages concurrently for different ids. Needs to be static so that when using a chained message listener and + * shared destinations between multiple PPPs, it gets notified about all replies, not just those that happen to + * be picked up by the PPP that it is atteched to. * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock - * pair. Obtian read lock on all messages, before decrementing the message count. At the end of the on message - * method add a block that obtains the write lock for the very last message, releases any waiting producer. Means - * that the last message waits until all other messages have been handled before releasing producers but allows - * messages to be processed concurrently, unlike the current synchronized block. - * + * pair. Obtian read lock on all messages, before decrementing the message count. At the end of the on message + * method add a block that obtains the write lock for the very last message, releases any waiting producer. Means + * that the last message waits until all other messages have been handled before releasing producers but allows + * messages to be processed concurrently, unlike the current synchronized block. * @todo Need to multiply up the number of expected messages for pubsub tests as each can be received by many consumers? */ public class PingPongProducer implements Runnable, MessageListener, ExceptionListener { private static final Logger _logger = Logger.getLogger(PingPongProducer.class); - /** Holds the name of the property to get the test message size from. */ + /** + * Holds the name of the property to get the test message size from. + */ public static final String MESSAGE_SIZE_PROPNAME = "messagesize"; - /** Holds the name of the property to get the ping queue name from. */ + /** + * Holds the name of the property to get the ping queue name from. + */ public static final String PING_QUEUE_NAME_PROPNAME = "destinationname"; - /** Holds the name of the property to get the test delivery mode from. */ + /** + * Holds the name of the property to get the test delivery mode from. + */ public static final String PERSISTENT_MODE_PROPNAME = "persistent"; - /** Holds the name of the property to get the test transactional mode from. */ + /** + * Holds the name of the property to get the test transactional mode from. + */ public static final String TRANSACTED_PROPNAME = "transacted"; - /** Holds the name of the property to get the test broker url from. */ + /** + * Holds the name of the property to get the test broker url from. + */ public static final String BROKER_PROPNAME = "broker"; - /** Holds the name of the property to get the test broker virtual path. */ + /** + * Holds the name of the property to get the test broker virtual path. + */ public static final String VIRTUAL_PATH_PROPNAME = "virtualPath"; - /** Holds the name of the property to get the message rate from. */ + /** + * Holds the name of the property to get the message rate from. + */ public static final String RATE_PROPNAME = "rate"; public static final String VERBOSE_OUTPUT_PROPNAME = "verbose"; - /** Holds the true or false depending on wether it is P2P test or PubSub */ + /** + * Holds the true or false depending on wether it is P2P test or PubSub + */ public static final String IS_PUBSUB_PROPNAME = "pubsub"; public static final String FAIL_AFTER_COMMIT_PROPNAME = "FailAfterCommit"; @@ -141,96 +153,147 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public static final String PING_DESTINATION_COUNT_PROPNAME = "destinationscount"; - /** Holds the name of the property to get the waiting timeout for response messages. */ + /** + * Holds the name of the property to get the waiting timeout for response messages. + */ public static final String TIMEOUT_PROPNAME = "timeout"; public static final String COMMIT_BATCH_SIZE_PROPNAME = "CommitBatchSize"; public static final String UNIQUE_PROPNAME = "uniqueDests"; - /** Used to set up a default message size. */ + /** + * Used to set up a default message size. + */ public static final int DEFAULT_MESSAGE_SIZE = 0; - /** Holds the name of the default destination to send pings on. */ + /** + * Holds the name of the default destination to send pings on. + */ public static final String DEFAULT_PING_DESTINATION_NAME = "ping"; - /** Defines the default number of destinations to ping. */ + /** + * Defines the default number of destinations to ping. + */ public static final int DEFAULT_DESTINATION_COUNT = 1; - /** Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. */ + /** + * Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. + */ public static final int DEFAULT_RATE = 0; - /** Defines the default wait between pings. */ + /** + * Defines the default wait between pings. + */ public static final long DEFAULT_SLEEP_TIME = 250; - /** Default time to wait before assuming that a ping has timed out. */ + /** + * Default time to wait before assuming that a ping has timed out. + */ public static final long DEFAULT_TIMEOUT = 30000; - /** Defines the default number of pings to send in each transaction when running transactionally. */ + /** + * Defines the default number of pings to send in each transaction when running transactionally. + */ public static final int DEFAULT_TX_BATCH_SIZE = 100; - /** Defines the default prefetch size to use when consuming messages. */ + /** + * Defines the default prefetch size to use when consuming messages. + */ public static final int DEFAULT_PREFETCH = 100; - /** Defines the default value of the no local flag to use when consuming messages. */ + /** + * Defines the default value of the no local flag to use when consuming messages. + */ public static final boolean DEFAULT_NO_LOCAL = false; - /** Defines the default value of the exclusive flag to use when consuming messages. */ + /** + * Defines the default value of the exclusive flag to use when consuming messages. + */ public static final boolean DEFAULT_EXCLUSIVE = false; - /** Holds the message delivery mode to use for the test. */ + /** + * Holds the message delivery mode to use for the test. + */ public static final boolean DEFAULT_PERSISTENT_MODE = false; - /** Holds the transactional mode to use for the test. */ + /** + * Holds the transactional mode to use for the test. + */ public static final boolean DEFAULT_TRANSACTED = false; - /** Holds the default broker url for the test. */ + /** + * Holds the default broker url for the test. + */ public static final String DEFAULT_BROKER = "tcp://localhost:5672"; - /** Holds the default virtual path for the test. */ + /** + * Holds the default virtual path for the test. + */ public static final String DEFAULT_VIRTUAL_PATH = "test"; - /** Holds the pub/sub mode default, true means ping a topic, false means ping a queue. */ + /** + * Holds the pub/sub mode default, true means ping a topic, false means ping a queue. + */ public static final boolean DEFAULT_PUBSUB = false; - /** Holds the default broker log on username. */ + /** + * Holds the default broker log on username. + */ public static final String DEFAULT_USERNAME = "guest"; - /** Holds the default broker log on password. */ + /** + * Holds the default broker log on password. + */ public static final String DEFAULT_PASSWORD = "guest"; - /** Holds the default message selector. */ + /** + * Holds the default message selector. + */ public static final String DEFAULT_SELECTOR = null; - /** Holds the default failover after commit test flag. */ + /** + * Holds the default failover after commit test flag. + */ public static final String DEFAULT_FAIL_AFTER_COMMIT = "false"; - /** Holds the default failover before commit test flag. */ + /** + * Holds the default failover before commit test flag. + */ public static final String DEFAULT_FAIL_BEFORE_COMMIT = "false"; - /** Holds the default failover after send test flag. */ + /** + * Holds the default failover after send test flag. + */ public static final String DEFAULT_FAIL_AFTER_SEND = "false"; - /** Holds the default failover before send test flag. */ + /** + * Holds the default failover before send test flag. + */ public static final String DEFAULT_FAIL_BEFORE_SEND = "false"; - /** Holds the default failover only once flag, true means only do one failover, false means failover on every commit cycle. */ + /** + * Holds the default failover only once flag, true means only do one failover, false means failover on every commit cycle. + */ public static final String DEFAULT_FAIL_ONCE = "true"; - /** Holds the default verbose mode. */ + /** + * Holds the default verbose mode. + */ public static final boolean DEFAULT_VERBOSE = false; public static final boolean DEFAULT_UNIQUE = true; - /** Holds the name of the property to store nanosecond timestamps in ping messages with. */ + /** + * Holds the name of the property to store nanosecond timestamps in ping messages with. + */ public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp"; - /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ + /** + * A source for providing sequential unique correlation ids. These will be unique within the same JVM. + */ private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); - /** A source for providing unique ids to PingPongProducer. */ - private static AtomicInteger _pingProducerIdGenerator; - /** * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross * multiple ping producers on the same JVM. @@ -238,9 +301,11 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /*private static Map trafficLights = Collections.synchronizedMap(new HashMap());*/ private static Map perCorrelationIds = - Collections.synchronizedMap(new HashMap()); + Collections.synchronizedMap(new HashMap()); - /** A convenient formatter to use when time stamping output. */ + /** + * A convenient formatter to use when time stamping output. + */ protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); /** @@ -249,69 +314,118 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ protected static AtomicInteger _queueJVMSequenceID = new AtomicInteger(); - /** Destination where the response messages will arrive. */ + /** + * Destination where the response messages will arrive. + */ private Destination _replyDestination; - /** Determines whether this producer sends persistent messages. */ + /** + * Determines whether this producer sends persistent messages. + */ protected boolean _persistent; - /** Determines what size of messages this producer sends. */ + /** + * Determines what size of messages this producer sends. + */ protected int _messageSize; - /** Used to indicate that the ping loop should print out whenever it pings. */ + /** + * Used to indicate that the ping loop should print out whenever it pings. + */ protected boolean _verbose = false; - /** Holds the session on which ping replies are received. */ + /** + * Holds the session on which ping replies are received. + */ protected Session _consumerSession; - /** Used to restrict the sending rate to a specified limit. */ + /** + * Used to restrict the sending rate to a specified limit. + */ private Throttle _rateLimiter = null; - /** Holds a message listener that this message listener chains all its messages to. */ + /** + * Holds a message listener that this message listener chains all its messages to. + */ private ChainedMessageListener _chainedMessageListener = null; - /** Flag used to indicate if this is a point to point or pub/sub ping client. */ + /** + * Flag used to indicate if this is a point to point or pub/sub ping client. + */ protected boolean _isPubSub = false; + /** + * Flag used to indicate if the destinations should be unique client. + */ + protected static boolean _isUnique = false; + /** * This id generator is used to generates ids that are only unique within this pinger. Creating multiple pingers * on the same JVM using this id generator will allow them to ping on the same queues. */ protected AtomicInteger _queueSharedId = new AtomicInteger(); - /** Used to tell the ping loop when to terminate, it only runs while this is true. */ + /** + * Used to tell the ping loop when to terminate, it only runs while this is true. + */ protected boolean _publish = true; - /** Holds the connection to the broker. */ + /** + * Holds the connection to the broker. + */ private Connection _connection; - /** Holds the producer session, needed to create ping messages. */ + /** + * Holds the producer session, needed to create ping messages. + */ private Session _producerSession; - /** Holds the set of destiniations that this ping producer pings. */ + /** + * Holds the set of destiniations that this ping producer pings. + */ protected List _pingDestinations = new ArrayList(); - /** Holds the message producer to send the pings through. */ + /** + * Holds the message producer to send the pings through. + */ protected MessageProducer _producer; - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ + /** + * Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. + */ protected boolean _failBeforeCommit = false; - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ + /** + * Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. + */ protected boolean _failAfterCommit = false; - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ + /** + * Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. + */ protected boolean _failBeforeSend = false; - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ + /** + * Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. + */ protected boolean _failAfterSend = false; - /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ + /** + * Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. + */ protected boolean _failOnce = true; - /** Holds the number of sends that should be performed in every transaction when using transactions. */ + /** + * Holds the number of sends that should be performed in every transaction when using transactions. + */ protected int _txBatchSize = 1; + /** + * Holds the number of consumers that will be attached to each topic. + * Each pings will result in a reply from each of the attached clients + */ + static int _consumersPerTopic = 1; + /** * Creates a ping producer with the specified parameters, of which there are many. See their individual comments * for details. This constructor creates a connection to the broker and creates producer and consumer sessions on it, @@ -339,7 +453,6 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * possible, with no rate restriction. * @param pubsub True to ping topics, false to ping queues. * @param unique True to use unique destinations for each ping pong producer, false to share. - * * @throws Exception Any exceptions are allowed to fall through. */ public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, @@ -369,6 +482,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _failOnce = failOnce; _txBatchSize = txBatchSize; _isPubSub = pubsub; + _isUnique = unique; // Check that one or more destinations were specified. if (noOfDestinations < 1) @@ -407,6 +521,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * to be started to bounce the pings back again. * * @param args The command line arguments. + * @throws Exception When something went wrong with the test */ public static void main(String[] args) throws Exception { @@ -479,9 +594,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Create a ping producer to handle the request/wait/reply cycle. PingPongProducer pingProducer = - new PingPongProducer(brokerDetails, DEFAULT_USERNAME, DEFAULT_PASSWORD, virtualpath, destName, selector, - transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, - beforeSend, failOnce, batchSize, destCount, rate, pubsub, false); + new PingPongProducer(brokerDetails, DEFAULT_USERNAME, DEFAULT_PASSWORD, virtualpath, destName, selector, + transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, + beforeSend, failOnce, batchSize, destCount, rate, pubsub, false); pingProducer.getConnection().start(); @@ -511,7 +626,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis Thread.sleep(sleepTime); } catch (InterruptedException ie) - { } + { + //ignore + } } } @@ -555,11 +672,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * @param rootName The root of the name, or actual name if only one is being created. * @param unique true to make the destinations unique to this pinger, false to share * the numbering with all pingers on the same JVM. - * * @throws JMSException Any JMSExceptions are allowed to fall through. */ public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique) - throws JMSException + throws JMSException { _logger.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " + selector + ", String rootName = " + rootName + ", boolean unique = " @@ -568,7 +684,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Create the desired number of ping destinations and consumers for them. for (int i = 0; i < noOfDestinations; i++) { - AMQDestination destination = null; + AMQDestination destination; int id; @@ -701,11 +817,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * @param message The message to send. * @param numPings The number of ping messages to send. * @param timeout The timeout in milliseconds. - * * @return The number of replies received. This may be less than the number sent if the timeout terminated the * wait for all prematurely. - * - * @throws JMSException All underlying JMSExceptions are allowed to fall through. + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + * @throws InterruptedException When interrupted by a timeout. */ public int pingAndWaitForReply(Message message, int numPings, long timeout) throws JMSException, InterruptedException { @@ -727,14 +842,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * @param numPings The number of ping messages to send. * @param timeout The timeout in milliseconds. * @param messageCorrelationId The message correlation id. - * * @return The number of replies received. This may be less than the number sent if the timeout terminated the * wait for all prematurely. - * - * @throws JMSException All underlying JMSExceptions are allowed to fall through. + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + * @throws InterruptedException When interrupted by a timeout */ public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) - throws JMSException, InterruptedException + throws JMSException, InterruptedException { _logger.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called"); @@ -747,7 +861,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // chained message listener must be called before this sender can be unblocked, but that decrementing the // countdown needs to be done before the chained listener can be called. PerCorrelationId perCorrelationId = new PerCorrelationId(); - perCorrelationId.trafficLight = new CountDownLatch(numPings + 1); + + perCorrelationId.trafficLight = new CountDownLatch(getExpectedNumPings(numPings) + 1); perCorrelationIds.put(messageCorrelationId, perCorrelationId); // Set up the current time as the start time for pinging on the correlation id. This is used to determine @@ -767,11 +882,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis perCorrelationId.trafficLight.await(timeout, TimeUnit.MILLISECONDS); // Work out how many replies were receieved. - numReplies = numPings - (int) perCorrelationId.trafficLight.getCount(); - allMessagesReceived = numReplies >= numPings; + numReplies = getExpectedNumPings(numPings) - (int) perCorrelationId.trafficLight.getCount(); + + allMessagesReceived = numReplies == getExpectedNumPings(numPings); - _logger.debug("numReplies = "+ numReplies); - _logger.debug("allMessagesReceived = "+ allMessagesReceived); + _logger.debug("numReplies = " + numReplies); + _logger.debug("allMessagesReceived = " + allMessagesReceived); // Recheck the timeout condition. long now = System.nanoTime(); @@ -783,7 +899,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } while (!timedOut && !allMessagesReceived); - if ((numReplies < numPings) && _verbose) + if ((numReplies < getExpectedNumPings(numPings)) && _verbose) { _logger.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); } @@ -812,7 +928,6 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * @param message The message to send. * @param numPings The number of pings to send. * @param messageCorrelationId A correlation id to place on all messages sent. - * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException @@ -927,9 +1042,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * @param replyQueue The reply-to destination for the message. * @param messageSize The desired size of the message in bytes. * @param persistent true if the message should use persistent delivery, false otherwise. - * * @return A freshly generated test message. - * * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. */ public ObjectMessage getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException @@ -984,12 +1097,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public Thread getShutdownHook() { return new Thread(new Runnable() + { + public void run() { - public void run() - { - stop(); - } - }); + stop(); + } + }); } /** @@ -1007,7 +1120,6 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * * @param destinations The destinations to listen to. * @param selector A selector to filter the messages with. - * * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through. */ public void createReplyConsumers(Collection destinations, String selector) throws JMSException @@ -1019,8 +1131,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { // Create a consumer for the destination and set this pinger to listen to its messages. MessageConsumer consumer = - _consumerSession.createConsumer(destination, DEFAULT_PREFETCH, DEFAULT_NO_LOCAL, DEFAULT_EXCLUSIVE, - selector); + _consumerSession.createConsumer(destination, DEFAULT_PREFETCH, DEFAULT_NO_LOCAL, DEFAULT_EXCLUSIVE, + selector); consumer.setMessageListener(this); } } @@ -1043,19 +1155,20 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** * Convenience method to commit the transaction on the specified session. If the session to commit on is not * a transactional session, this method does nothing (unless the failover after send flag is set). - * + *

    *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit * is applied. This flag applies whether the pinger is transactional or not. - * + *

    *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker * after the commit is applied. These flags will only apply if using a transactional pinger. * + * @param session The session to commit * @throws javax.jms.JMSException If the commit fails and then the rollback fails. - * - * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit - * method, because commits only apply to transactional pingers, but fail after send applied to transactional - * and non-transactional alike. + *

    + * //todo @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit + * method, because commits only apply to transactional pingers, but fail after send applied to transactional + * and non-transactional alike. */ protected void commitTx(Session session) throws JMSException { @@ -1136,7 +1249,6 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * * @param destination The destination to send to. * @param message The message to send. - * * @throws javax.jms.JMSException All underlying JMSExceptions are allowed to fall through. */ protected void sendMessage(Destination destination, Message message) throws JMSException @@ -1174,17 +1286,35 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis System.in.read(); } catch (IOException e) - { } + { + //ignore + } System.out.println("Continuing."); } + /** + * This value will be changed by PingClient to represent the number of clients connected to each topic. + * + * @return int The number of consumers subscribing to each topic. + */ + public int getConsumersPerTopic() + { + return _consumersPerTopic; + } + + public int getExpectedNumPings(int numpings) + { + return numpings * getConsumersPerTopic(); + } + + /** * Defines a chained message listener interface that can be attached to this pinger. Whenever this pinger's * {@link PingPongProducer#onMessage} method is called, the chained listener set through the * {@link PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected * count of messages with that correlation id. - * + *

    * Provided only one pinger is producing messages with that correlation id, the chained listener will always be * given unique message counts. It will always be called while the producer waiting for all messages to arrive is * still blocked. @@ -1200,10 +1330,14 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ protected static class PerCorrelationId { - /** Holds a countdown on number of expected messages. */ + /** + * Holds a countdown on number of expected messages. + */ CountDownLatch trafficLight; - /** Holds the last timestamp that the timeout was reset to. */ + /** + * Holds the last timestamp that the timeout was reset to. + */ Long timeOutStart; } } -- cgit v1.2.1 From 59f51de1dd822732505bac83016dd1312a2ac11f Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 12 Feb 2007 13:25:36 +0000 Subject: (Patch submitted by Rupert Smith) Qpid-360 fixes. Message type defaults to ByteMessage when not specified. Unknown destination type is used as default when not specified. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@506439 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/topic/Listener.java | 279 ++++++++++++++++----- .../java/org/apache/qpid/topic/MessageFactory.java | 47 ++-- 2 files changed, 242 insertions(+), 84 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java index 47c608cfe4..76a0690b8c 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java @@ -7,9 +7,9 @@ * 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 @@ -20,122 +20,277 @@ */ package org.apache.qpid.topic; -import javax.jms.Connection; -import javax.jms.Message; -import javax.jms.MessageListener; -import javax.jms.MessageProducer; -import javax.jms.Session; +import java.util.Random; + +import javax.jms.*; + +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; + +/** + * This class has not kept up to date with the topic_listener in the cpp tests. It should provide identical behaviour for + * cross testing the java and cpp clients. + * + *

    How the cpp topic_publisher operates: + * It publishes text messages to the default topic exchange, on virtual host "/test", on the topic "topic_control", for + * the specified number of test messages to be sent. + * It publishes a report request message (on same topic), with the header text field "TYPE", value "REPORT_REQUEST", + * optionally within a transaction, and waits for the specified number of consumers to reply to this request. The + * listeners should reply to this message on a queue named "response", on virtual host "/test", with some sort of message + * about the number of messages received and how long it took, although the publisher never looks at the message content. + * The publisher then send a message (on the same topic), with the header text field "TYPE", value "TERMINATION_REQUEST", + * which the listener should close its connection and terminate upon receipt of. + * + * @deprecated Use PingPongBouncer instead once the below todo is completed. + * + * @todo Make the functionality of this class available through PingPongBouncer. Rename PingPongBouncer to + * PingListener and make its bouncing functionality optional, either through a switch or as an extending class + * called PingBouncer. Want to have as few ping classes as possible with configurable behaviour, re-using code + * accross p2p and topic style tests in almost all cases. + */ public class Listener implements MessageListener { + private static Logger log = Logger.getLogger(Listener.class); + + private static final char[] DATA = "abcdefghijklmnopqrstuvwxyz".toCharArray(); + public static final String CONTROL_TOPIC = "topic_control"; + public static final String RESPONSE_QUEUE = "response"; + + private final Topic _topic; + //private final Topic _control; + + private final Queue _response; + + private final byte[] _payload; + + /** Holds the connection to listen on. */ private final Connection _connection; + + /** Holds the producer to send control messages on. */ private final MessageProducer _controller; + + /** Holds the JMS session. */ private final javax.jms.Session _session; - private final MessageFactory _factory; + + /** Holds a flag to indicate that a timer has begun on the first message. Reset when report is sent. */ private boolean init; + + /** Holds the count of messages received by this listener. */ private int count; - private long start; - Listener(Connection connection, int ackMode) throws Exception - { - this(connection, ackMode, null); - } + /** Used to hold the start time of the first message. */ + private long start; + private static String clientId; Listener(Connection connection, int ackMode, String name) throws Exception { + log.debug("Listener(Connection connection = " + connection + ", int ackMode = " + ackMode + ", String name = " + name + + "): called"); + _connection = connection; _session = connection.createSession(false, ackMode); - _factory = new MessageFactory(_session); - //register for events - if(name == null) + if (_session instanceof AMQSession) { - _factory.createTopicConsumer().setMessageListener(this); + _topic = new AMQTopic(CONTROL_TOPIC); + //_control = new AMQTopic(CONTROL_TOPIC); + _response = new AMQQueue(RESPONSE_QUEUE); } else { - _factory.createDurableTopicConsumer(name).setMessageListener(this); + _topic = _session.createTopic(CONTROL_TOPIC); + //_control = _session.createTopic(CONTROL_TOPIC); + _response = _session.createQueue(RESPONSE_QUEUE); } - _connection.start(); + int size = 256; - _controller = _factory.createControlPublisher(); - System.out.println("Waiting for messages " + - Config.getAckModeDescription(ackMode) - + (name == null ? "" : " (subscribed with name " + name + " and client id " + connection.getClientID() + ")") - + "..."); + _payload = new byte[size]; - } + for (int i = 0; i < size; i++) + { + _payload[i] = (byte) DATA[i % DATA.length]; + } - private void shutdown() - { - try + //register for events + if (name == null) { - _session.close(); - _connection.stop(); - _connection.close(); + log.debug("Calling _factory.createTopicConsumer().setMessageListener(this)"); + createTopicConsumer().setMessageListener(this); } - catch(Exception e) + else { - e.printStackTrace(System.out); + log.debug("Calling createDurableTopicConsumer(name).setMessageListener(this)"); + createDurableTopicConsumer(name).setMessageListener(this); } + + _connection.start(); + + _controller = createControlPublisher(); + System.out.println("Waiting for messages " + Config.getAckModeDescription(ackMode) + + + ((name == null) + ? "" : (" (subscribed with name " + name + " and client id " + connection.getClientID() + ")")) + + "..."); } - private void report() + public static void main(String[] argv) throws Exception { - try - { - String msg = getReport(); - _controller.send(_factory.createReportResponseMessage(msg)); - System.out.println("Sent report: " + msg); - } - catch(Exception e) + clientId = "Listener-" + System.currentTimeMillis(); + + NDC.push(clientId); + + Config config = new Config(); + config.setOptions(argv); + + //Connection con = config.createConnection(); + Connection con = + new AMQConnection("amqp://guest:guest@testid/test?brokerlist='" + config.getHost() + ":" + config.getPort() + + "'"); + + if (config.getClientId() != null) { - e.printStackTrace(System.out); + con.setClientID(config.getClientId()); } + + new Listener(con, config.getAckMode(), config.getSubscriptionId()); + + NDC.pop(); + NDC.remove(); } - private String getReport() + /** + * Checks whether or not a text field on a message has the specified value. + * + * @param m The message to check. + * @param fieldName The name of the field to check. + * @param value The expected value of the field to compare with. + * + * @return trueIf the specified field has the specified value, fals otherwise. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + private static boolean checkTextField(Message m, String fieldName, String value) throws JMSException { - long time = (System.currentTimeMillis() - start); - return "Received " + count + " in " + time + "ms"; + log.debug("private static boolean checkTextField(Message m = " + m + ", String fieldName = " + fieldName + + ", String value = " + value + "): called"); + + String comp = m.getStringProperty(fieldName); + + return (comp != null) && comp.equals(value); } public void onMessage(Message message) { - if(!init) + NDC.push(clientId); + + log.debug("public void onMessage(Message message): called"); + + if (!init) { - start = System.currentTimeMillis(); + start = System.nanoTime() / 1000000; count = 0; init = true; } - if(_factory.isShutdown(message)) + try { - shutdown(); + if (isShutdown(message)) + { + shutdown(); + } + else if (isReport(message)) + { + //send a report: + report(); + init = false; + } } - else if(_factory.isReport(message)) + catch (JMSException e) { - //send a report: - report(); - init = false; + log.warn("There was a JMSException during onMessage.", e); } - else if (++count % 100 == 0) + finally { - System.out.println("Received " + count + " messages."); + NDC.pop(); } } - public static void main(String[] argv) throws Exception + Message createReportResponseMessage(String msg) throws JMSException { - Config config = new Config(); - config.setOptions(argv); + return _session.createTextMessage(msg); + } + + boolean isShutdown(Message m) throws JMSException + { + boolean result = checkTextField(m, "TYPE", "TERMINATION_REQUEST"); + + log.debug("isShutdown = " + result); + + return result; + } + + boolean isReport(Message m) throws JMSException + { + boolean result = checkTextField(m, "TYPE", "REPORT_REQUEST"); + + log.debug("isReport = " + result); + + return result; + } + + MessageConsumer createTopicConsumer() throws Exception + { + return _session.createConsumer(_topic); + } + + MessageConsumer createDurableTopicConsumer(String name) throws Exception + { + return _session.createDurableSubscriber(_topic, name); + } + + MessageProducer createControlPublisher() throws Exception + { + return _session.createProducer(_response); + } - Connection con = config.createConnection(); - if(config.getClientId() != null) + private void shutdown() + { + try { - con.setClientID(config.getClientId()); + _session.close(); + _connection.stop(); + _connection.close(); } - new Listener(con, config.getAckMode(), config.getSubscriptionId()); + catch (Exception e) + { + e.printStackTrace(System.out); + } + } + + private void report() + { + try + { + String msg = getReport(); + _controller.send(createReportResponseMessage(msg)); + System.out.println("Sent report: " + msg); + } + catch (Exception e) + { + e.printStackTrace(System.out); + } + } + + private String getReport() + { + long time = ((System.nanoTime() / 1000000) - start); + + return "Received " + count + " in " + time + "ms"; } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java index 1520f18408..8b87f76c3e 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java @@ -7,9 +7,9 @@ * 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 @@ -20,11 +20,11 @@ */ package org.apache.qpid.topic; +import javax.jms.*; + import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQTopic; -import javax.jms.*; - /** */ class MessageFactory @@ -36,7 +36,6 @@ class MessageFactory private final Topic _control; private final byte[] _payload; - MessageFactory(Session session) throws JMSException { this(session, 256); @@ -45,24 +44,39 @@ class MessageFactory MessageFactory(Session session, int size) throws JMSException { _session = session; - if(session instanceof AMQSession) + if (session instanceof AMQSession) { - _topic = new AMQTopic("topictest.messages"); + _topic = new AMQTopic("topic_control"); _control = new AMQTopic("topictest.control"); } else { - _topic = session.createTopic("topictest.messages"); + _topic = session.createTopic("topic_control"); _control = session.createTopic("topictest.control"); } + _payload = new byte[size]; - for(int i = 0; i < size; i++) + for (int i = 0; i < size; i++) { _payload[i] = (byte) DATA[i % DATA.length]; } } + private static boolean checkText(Message m, String s) + { + try + { + return (m instanceof TextMessage) && ((TextMessage) m).getText().equals(s); + } + catch (JMSException e) + { + e.printStackTrace(System.out); + + return false; + } + } + Topic getTopic() { return _topic; @@ -72,6 +86,7 @@ class MessageFactory { BytesMessage msg = _session.createBytesMessage(); msg.writeBytes(_payload); + return msg; } @@ -109,6 +124,7 @@ class MessageFactory catch (JMSException e) { e.printStackTrace(System.out); + return e.toString(); } } @@ -137,17 +153,4 @@ class MessageFactory { return _session.createProducer(_control); } - - private static boolean checkText(Message m, String s) - { - try - { - return m instanceof TextMessage && ((TextMessage) m).getText().equals(s); - } - catch (JMSException e) - { - e.printStackTrace(System.out); - return false; - } - } } -- cgit v1.2.1 From 21575ca311935f0c308df0062c274f8ce1e9cb4a Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Fri, 16 Feb 2007 23:11:41 +0000 Subject: QPID-375 : remove assumptions on standard exchanges (amq.direct, amq.topic, etc), allow other exchanges to be created through virtualhosts.xml git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@508649 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java | 5 +++-- .../src/main/java/org/apache/qpid/requestreply/PingPongProducer.java | 5 +++-- .../java/perftests/src/main/java/org/apache/qpid/topic/Listener.java | 5 +++-- .../src/main/java/org/apache/qpid/topic/MessageFactory.java | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java index ab795d0459..78ab7c4c73 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -35,6 +35,7 @@ import org.apache.qpid.client.AMQTopic; import org.apache.qpid.jms.ConnectionListener; import org.apache.qpid.jms.Session; import org.apache.qpid.topic.Config; +import org.apache.qpid.exchange.ExchangeDefaults; /** * PingPongBouncer is a message listener the bounces back messages to their reply to destination. This is used to return @@ -414,11 +415,11 @@ public class PingPongBouncer implements MessageListener { if (isPubSub()) { - _consumerDestination = new AMQTopic(name); + _consumerDestination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, name); } else { - _consumerDestination = new AMQQueue(name); + _consumerDestination = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, name); } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 8def95f7b1..57d5c37fc6 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -43,6 +43,7 @@ import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; import org.apache.qpid.topic.Config; +import org.apache.qpid.exchange.ExchangeDefaults; import uk.co.thebadgerset.junit.extensions.BatchedThrottle; import uk.co.thebadgerset.junit.extensions.Throttle; @@ -704,13 +705,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis if (_isPubSub) { _logger.debug("Creating topics."); - destination = new AMQTopic(rootName + id); + destination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id); } // Otherwise this is a p2p pinger, in which case create queues. else { _logger.debug("Creating queues."); - destination = new AMQQueue(rootName + id); + destination = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, rootName + id); } // Keep the destination. diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java index 76a0690b8c..54f5a0f660 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java @@ -31,6 +31,7 @@ import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.exchange.ExchangeDefaults; /** * This class has not kept up to date with the topic_listener in the cpp tests. It should provide identical behaviour for @@ -97,9 +98,9 @@ public class Listener implements MessageListener if (_session instanceof AMQSession) { - _topic = new AMQTopic(CONTROL_TOPIC); + _topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, CONTROL_TOPIC); //_control = new AMQTopic(CONTROL_TOPIC); - _response = new AMQQueue(RESPONSE_QUEUE); + _response = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, RESPONSE_QUEUE); } else { diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java index 8b87f76c3e..4efdc1cb56 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java @@ -24,6 +24,7 @@ import javax.jms.*; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.exchange.ExchangeDefaults; /** */ @@ -46,8 +47,8 @@ class MessageFactory _session = session; if (session instanceof AMQSession) { - _topic = new AMQTopic("topic_control"); - _control = new AMQTopic("topictest.control"); + _topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, "topic_control"); + _control = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, "topictest.control"); } else { -- cgit v1.2.1 From 20098b5a549820ad27282bb5760890674535bbdb Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 28 Feb 2007 11:05:20 +0000 Subject: (Patch submitted by Rupert Smith). java_iop.diff This adds some interop tests (which are just copies of the existing topic tests) in a new integrationtests module. The java 1.4. client build has been updated to be able to run these tests. They succesfully talk to each other and the .net code. This is intended to be a starting point of a more in depth interop test as per the spec, but does not implement what is in the draft spec yet. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@512699 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/topic/Listener.java | 56 ++++++++++++---------- 1 file changed, 31 insertions(+), 25 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java index 54f5a0f660..6dcea42bfe 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java @@ -47,18 +47,14 @@ import org.apache.qpid.exchange.ExchangeDefaults; * The publisher then send a message (on the same topic), with the header text field "TYPE", value "TERMINATION_REQUEST", * which the listener should close its connection and terminate upon receipt of. * - * @deprecated Use PingPongBouncer instead once the below todo is completed. - * - * @todo Make the functionality of this class available through PingPongBouncer. Rename PingPongBouncer to - * PingListener and make its bouncing functionality optional, either through a switch or as an extending class - * called PingBouncer. Want to have as few ping classes as possible with configurable behaviour, re-using code - * accross p2p and topic style tests in almost all cases. + * @todo I've added lots of field table types in the report message, just to check if the other end can decode them + * correctly. Not really the right place to test this, so remove them from + * {@link #createReportResponseMessage(String)} once a better test exists. */ public class Listener implements MessageListener { private static Logger log = Logger.getLogger(Listener.class); - private static final char[] DATA = "abcdefghijklmnopqrstuvwxyz".toCharArray(); public static final String CONTROL_TOPIC = "topic_control"; public static final String RESPONSE_QUEUE = "response"; @@ -67,8 +63,6 @@ public class Listener implements MessageListener private final Queue _response; - private final byte[] _payload; - /** Holds the connection to listen on. */ private final Connection _connection; @@ -109,15 +103,6 @@ public class Listener implements MessageListener _response = _session.createQueue(RESPONSE_QUEUE); } - int size = 256; - - _payload = new byte[size]; - - for (int i = 0; i < size; i++) - { - _payload[i] = (byte) DATA[i % DATA.length]; - } - //register for events if (name == null) { @@ -182,15 +167,19 @@ public class Listener implements MessageListener + ", String value = " + value + "): called"); String comp = m.getStringProperty(fieldName); + log.debug("comp = " + comp); + + boolean result = (comp != null) && comp.equals(value); + log.debug("result = " + result); - return (comp != null) && comp.equals(value); + return result; } public void onMessage(Message message) { NDC.push(clientId); - log.debug("public void onMessage(Message message): called"); + log.debug("public void onMessage(Message message = " + message + "): called"); if (!init) { @@ -203,11 +192,14 @@ public class Listener implements MessageListener { if (isShutdown(message)) { + log.debug("Got a shutdown message."); shutdown(); } else if (isReport(message)) { - //send a report: + log.debug("Got a report request message."); + + // Send the report. report(); init = false; } @@ -224,14 +216,26 @@ public class Listener implements MessageListener Message createReportResponseMessage(String msg) throws JMSException { - return _session.createTextMessage(msg); + Message message = _session.createTextMessage(msg); + + // Shove some more field table type in the message just to see if the other end can handle it. + message.setBooleanProperty("BOOLEAN", true); + message.setByteProperty("BYTE", (byte) 5); + message.setDoubleProperty("DOUBLE", Math.PI); + message.setFloatProperty("FLOAT", 1.0f); + message.setIntProperty("INT", 1); + message.setShortProperty("SHORT", (short) 1); + message.setLongProperty("LONG", (long) 1827361278); + message.setStringProperty("STRING", "hello"); + + return message; } boolean isShutdown(Message m) throws JMSException { boolean result = checkTextField(m, "TYPE", "TERMINATION_REQUEST"); - log.debug("isShutdown = " + result); + //log.debug("isShutdown = " + result); return result; } @@ -240,7 +244,7 @@ public class Listener implements MessageListener { boolean result = checkTextField(m, "TYPE", "REPORT_REQUEST"); - log.debug("isReport = " + result); + //log.debug("isReport = " + result); return result; } @@ -276,11 +280,13 @@ public class Listener implements MessageListener private void report() { + log.debug("private void report(): called"); + try { String msg = getReport(); _controller.send(createReportResponseMessage(msg)); - System.out.println("Sent report: " + msg); + log.debug("Sent report: " + msg); } catch (Exception e) { -- cgit v1.2.1 From 106ecb152c2caeae83431c966b3442b8536eb850 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Mon, 5 Mar 2007 15:54:44 +0000 Subject: QPID-388 : hand merged the changes done in perftesting branch QPID-395 : hand merged the changes done in perftesting branch QPID-375 : default queue config properties should now be under tag git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@514703 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/ping/PingClient.java | 6 +- .../apache/qpid/requestreply/PingPongProducer.java | 64 +++++++++++++++++----- 2 files changed, 52 insertions(+), 18 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java index 1a37f47b35..013bda5927 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java @@ -73,11 +73,12 @@ public class PingClient extends PingPongProducer public PingClient(String brokerDetails, String username, String password, String virtualpath, String destinationName, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, - int txBatchSize, int noOfDestinations, int rate, boolean pubsub, boolean unique) throws Exception + int txBatchSize, int noOfDestinations, int rate, boolean pubsub, boolean unique, + int ackMode, long pausetime) throws Exception { super(brokerDetails, username, password, virtualpath, destinationName, selector, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, txBatchSize, noOfDestinations, rate, - pubsub, unique); + pubsub, unique, ackMode, pausetime); _pingClientCount++; } @@ -104,5 +105,4 @@ public class PingClient extends PingPongProducer return _pingClientCount; } } - } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 57d5c37fc6..f2fbd29314 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -163,6 +163,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public static final String UNIQUE_PROPNAME = "uniqueDests"; + public static final String ACK_MODE_PROPNAME = "ackMode"; + + public static final String PAUSE_AFTER_BATCH_PROPNAME = "pausetimeAfterEachBatch"; + /** * Used to set up a default message size. */ @@ -285,6 +289,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public static final boolean DEFAULT_UNIQUE = true; + public static final int DEFAULT_ACK_MODE = Session.NO_ACKNOWLEDGE; + /** * Holds the name of the property to store nanosecond timestamps in ping messages with. */ @@ -325,6 +331,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ protected boolean _persistent; + private int _ackMode = Session.NO_ACKNOWLEDGE; + /** * Determines what size of messages this producer sends. */ @@ -421,6 +429,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ protected int _txBatchSize = 1; + private static long _pausetimeAfterEachBatch = 0; + /** * Holds the number of consumers that will be attached to each topic. * Each pings will result in a reply from each of the attached clients @@ -460,7 +470,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis String destinationName, String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, int txBatchSize, int noOfDestinations, int rate, - boolean pubsub, boolean unique) throws Exception + boolean pubsub, boolean unique, int ackMode, long pause) throws Exception { _logger.debug("public PingPongProducer(String brokerDetails = " + brokerDetails + ", String username = " + username + ", String password = " + password + ", String virtualpath = " + virtualpath @@ -470,7 +480,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis + afterCommit + ", boolean beforeCommit = " + beforeCommit + ", boolean afterSend = " + afterSend + ", boolean beforeSend = " + beforeSend + ", boolean failOnce = " + failOnce + ", int txBatchSize = " + txBatchSize + ", int noOfDestinations = " + noOfDestinations + ", int rate = " + rate - + ", boolean pubsub = " + pubsub + ", boolean unique = " + unique + "): called"); + + ", boolean pubsub = " + pubsub + ", boolean unique = " + unique + + ", ackMode = " + ackMode + "): called"); // Keep all the relevant options. _persistent = persistent; @@ -484,7 +495,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _txBatchSize = txBatchSize; _isPubSub = pubsub; _isUnique = unique; - + _pausetimeAfterEachBatch = pause; + if (ackMode != 0) + { + _ackMode = ackMode; + } + // Check that one or more destinations were specified. if (noOfDestinations < 1) { @@ -498,8 +514,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _connection = new AMQConnection(brokerDetails, username, password, clientID, virtualpath); // Create transactional or non-transactional sessions, based on the command line arguments. - _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); - _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + _producerSession = (Session) getConnection().createSession(transacted, _ackMode); + _consumerSession = (Session) getConnection().createSession(transacted, _ackMode); // Set up a throttle to control the send rate, if a rate > 0 is specified. if (rate > 0) @@ -537,7 +553,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } String brokerDetails = config.getHost() + ":" + config.getPort(); - String virtualpath = "test"; + String virtualpath = DEFAULT_VIRTUAL_PATH; String selector = (config.getSelector() == null) ? DEFAULT_SELECTOR : config.getSelector(); boolean verbose = true; boolean transacted = config.isTransacted(); @@ -597,7 +613,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis PingPongProducer pingProducer = new PingPongProducer(brokerDetails, DEFAULT_USERNAME, DEFAULT_PASSWORD, virtualpath, destName, selector, transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, - beforeSend, failOnce, batchSize, destCount, rate, pubsub, false); + beforeSend, failOnce, batchSize, destCount, rate, pubsub, false, 0, 0); pingProducer.getConnection().start(); @@ -687,31 +703,31 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { AMQDestination destination; - int id; + String id; // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag. if (unique) { _logger.debug("Creating unique destinations."); - id = _queueJVMSequenceID.incrementAndGet(); + id = "_" + _queueJVMSequenceID.incrementAndGet() + "_" + _connection.getClientID(); } else { _logger.debug("Creating shared destinations."); - id = _queueSharedId.incrementAndGet(); + id = "_" + _queueSharedId.incrementAndGet(); } // Check if this is a pub/sub pinger, in which case create topics. if (_isPubSub) { - _logger.debug("Creating topics."); destination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id); + _logger.debug("Created topic " + destination); } // Otherwise this is a p2p pinger, in which case create queues. else { - _logger.debug("Creating queues."); destination = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, rootName + id); + _logger.debug("Created queue " + destination); } // Keep the destination. @@ -834,6 +850,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis return pingAndWaitForReply(message, numPings, timeout, messageCorrelationId); } + public int pingAndWaitForReply(int numPings, long timeout, String messageCorrelationId) + throws JMSException, InterruptedException + { + return pingAndWaitForReply(null, numPings, timeout, messageCorrelationId); + } + /** * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out * before a reply arrives, then a null reply is returned from this method. This method allows the caller to specify @@ -936,6 +958,11 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _logger.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings + ", String messageCorrelationId = " + messageCorrelationId + "): called"); + if (message == null) + { + message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent); + } + message.setJMSCorrelationID(messageCorrelationId); // Set up a committed flag to detect uncommitted messages at the end of the send loop. This may occurr if the @@ -967,6 +994,11 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { commitTx(_producerSession); committed = true; + /* This pause is required for some cases. eg in load testing when sessions are non-transacted the + Mina IO layer can't clear the cache in time. So this pause gives enough time for mina to clear + the cache (without this mina throws OutOfMemoryError). pause() will check if time is != 0 + */ + pause(_pausetimeAfterEachBatch); } // Spew out per message timings on every message sonly in verbose mode. @@ -1013,10 +1045,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } } - /*public Destination getReplyDestination() + public Destination getReplyDestination() { - return _replyDestination; - }*/ + return getReplyDestinations().get(0); + } /** * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set @@ -1203,7 +1235,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis doFailover(); } + long l = System.currentTimeMillis(); session.commit(); + _logger.debug("Time taken to commit :" + (System.currentTimeMillis() - l) + " ms" ); if (_failAfterCommit) { -- cgit v1.2.1 From 06f78cd04c96549c02a25baac80b7423ffe63903 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Fri, 16 Mar 2007 15:07:57 +0000 Subject: Added timeout to be passed on command line. Updated PingPongProducer.java to run it either continuously or for a fixed no of messages git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@518999 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongProducer.java | 41 ++++++++++++++++------ .../main/java/org/apache/qpid/topic/Config.java | 15 ++++++++ 2 files changed, 46 insertions(+), 10 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index f2fbd29314..16d46ce2b8 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -39,6 +39,7 @@ import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQNoConsumersException; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; @@ -559,11 +560,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis boolean transacted = config.isTransacted(); boolean persistent = config.usePersistentMessages(); int messageSize = (config.getPayload() != 0) ? config.getPayload() : DEFAULT_MESSAGE_SIZE; - //int messageCount = config.getMessages(); + int messageCount = config.getMessages(); int destCount = (config.getDestinationsCount() != 0) ? config.getDestinationsCount() : DEFAULT_DESTINATION_COUNT; int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : DEFAULT_TX_BATCH_SIZE; int rate = (config.getRate() != 0) ? config.getRate() : DEFAULT_RATE; boolean pubsub = config.isPubSub(); + long timeout = (config.getTimeout() != 0) ? config.getTimeout() : DEFAULT_TIMEOUT; String destName = config.getDestination(); if (destName == null) @@ -623,10 +625,19 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. pingProducer.getConnection().setExceptionListener(pingProducer); - // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. - Thread pingThread = new Thread(pingProducer); - pingThread.run(); - pingThread.join(); + // If messageount is 0, then continue sending + if (messageCount == 0) + { + // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. + Thread pingThread = new Thread(pingProducer); + pingThread.start(); + pingThread.join(); + } + else + { + pingProducer.ping(messageCount, timeout); + } + pingProducer.close(); } /** @@ -785,8 +796,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis if ((remainingCount % _txBatchSize) == 0) { commitTx(_consumerSession); + if (!_consumerSession.getTransacted() && + _consumerSession.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) + { + ((AMQSession)_consumerSession).acknowledge(); + } } - + // Forward the message and remaining count to any interested chained message listener. if (_chainedMessageListener != null) { @@ -1017,9 +1033,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * The ping loop implementation. This sends out pings waits for replies and inserts short pauses in between each. + * The ping implementation. This sends out pings waits for replies and inserts short pauses in between each. */ - public void pingLoop() + public void ping(int pingCount, long timeout) { try { @@ -1028,7 +1044,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); // Send the message and wait for a reply. - pingAndWaitForReply(msg, DEFAULT_TX_BATCH_SIZE, DEFAULT_TIMEOUT); + pingAndWaitForReply(msg, pingCount, timeout); // Introduce a short pause if desired. pause(DEFAULT_SLEEP_TIME); @@ -1045,6 +1061,11 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } } + public void ping() + { + ping(DEFAULT_TX_BATCH_SIZE, DEFAULT_TIMEOUT); + } + public Destination getReplyDestination() { return getReplyDestinations().get(0); @@ -1105,7 +1126,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Keep running until the publish flag is cleared. while (_publish) { - pingLoop(); + ping(); } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java index 60aa9f3930..342b28ca17 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java @@ -51,6 +51,7 @@ public class Config extends AbstractConfig implements ConnectorConfig private int batchSize; private int rate; private boolean ispubsub; + private long timeout; public Config() { @@ -161,6 +162,16 @@ public class Config extends AbstractConfig implements ConnectorConfig this.delay = delay; } + public long getTimeout() + { + return timeout; + } + + public void setTimeout(long time) + { + this.timeout = time; + } + public String getClientId() { return clientId; @@ -285,6 +296,10 @@ public class Config extends AbstractConfig implements ConnectorConfig { destinationName = value; } + else if("-timeout".equalsIgnoreCase(key)) + { + setTimeout(parseLong("Bad timeout data", value)); + } else { System.out.println("Ignoring unrecognised option: " + key); -- cgit v1.2.1 From a3cebeaad14bcc13bd432914f366571cc70aefd9 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Fri, 23 Mar 2007 12:59:39 +0000 Subject: Updated perftests from M2 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@521711 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongProducer.java | 809 +++++++++------------ 1 file changed, 364 insertions(+), 445 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 16d46ce2b8..2a3aff4692 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -39,281 +39,250 @@ import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQNoConsumersException; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; import org.apache.qpid.topic.Config; -import org.apache.qpid.exchange.ExchangeDefaults; import uk.co.thebadgerset.junit.extensions.BatchedThrottle; import uk.co.thebadgerset.junit.extensions.Throttle; /** - * PingPongProducer is a client that sends pings to a queue and waits for pongs to be bounced back by a bounce back - * client (see {@link PingPongBouncer} for the bounce back client). - *

    - *

    The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. - * This means that this class has to do some work to correlate pings with pongs; it expectes the original message - * correlation id in the ping to be bounced back in the reply correlation id. - *

    - *

    This ping tool accepts a vast number of configuration options, all of which are passed in to the constructor. - * It can ping topics or queues; ping multiple destinations; do persistent pings; send messages of any size; do pings - * within transactions; control the number of pings to send in each transaction; limit its sending rate; and perform - * failover testing. - *

    + * PingPongProducer is a client that sends test messages, and waits for replies to these messages. The replies may + * either be generated by another client (see {@link PingPongBouncer}, or an extension of it may be used that listens + * to its own messages and does not send replies (see {@link org.apache.qpid.ping.PingClient}). The intention of ping + * pong producer is that it is a swiss-army knife test client that makes almost every aspect of its behaviour + * configurable. + * + *

    The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. This + * means that this class has to do some work to correlate pings with pongs; it expectes the original message correlation + * id in the ping to be bounced back in the reply correlation id. + * + *

    This ping tool accepts a vast number of configuration options, all of which are passed in to the constructor. It + * can ping topics or queues; ping multiple destinations; do persistent pings; send messages of any size; do pings within + * transactions; control the number of pings to send in each transaction; limit its sending rate; and perform failover + * testing. A complete list of accepted parameters, default values and comments on their usage is provided here: + * + *

    + *
    CRC Card
    Parameter Default Comments + *
    messageSize 0 Message size in bytes. Not including any headers. + *
    destinationName ping The root name to use to generate destination names to ping. + *
    persistent false Determines whether peristent delivery is used. + *
    transacted false Determines whether messages are sent/received in transactions. + *
    broker tcp://localhost:5672 Determines the broker to connect to. + *
    virtualHost test Determines the virtual host to send all ping over. + *
    rate 0 The maximum rate (in hertz) to send messages at. 0 means no limit. + *
    verbose false The verbose flag for debugging. Prints to console on every message. + *
    pubsub false Whether to ping topics or queues. Uses p2p by default. + *
    failAfterCommit false Whether to prompt user to kill broker after a commit batch. + *
    failBeforeCommit false Whether to prompt user to kill broker before a commit batch. + *
    failAfterSend false Whether to prompt user to kill broker after a send. + *
    failBeforeSend false Whether to prompt user to kill broker before a send. + *
    failOnce true Whether to prompt for failover only once. + *
    username guest The username to access the broker with. + *
    password guest The password to access the broker with. + *
    selector null Not used. Defines a message selector to filter pings with. + *
    destinationCount 1 The number of receivers listening to the pings. + *
    timeout 30000 In milliseconds. The timeout to stop waiting for replies. + *
    commitBatchSize 1 The number of messages per transaction in transactional mode. + *
    uniqueDests true Whether each receiver only listens to one ping destination or all. + *
    ackMode NO_ACK The message acknowledgement mode. + *
    pauseBatch 0 In milliseconds. A pause to insert between transaction batches. + *
    + * *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop - * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so - * by starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is - * also registered to terminate the ping-pong loop cleanly. - *

    + * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so by + * starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is also + * registered to terminate the ping-pong loop cleanly. + * *

    *
    CRC Card
    Responsibilities Collaborations *
    Provide a ping and wait for all responses cycle. *
    Provide command line invocation to loop the ping cycle on a configurable broker url. *
    * - * @todo The use of a ping rate {@link #DEFAULT_RATE} and waits between pings {@link #DEFAULT_SLEEP_TIME} are overlapping. - * Use the rate and throttling only. Ideally, optionally pass the rate throttle into the ping method, throttle to - * be created and configured by the test runner from the -f command line option and made available through - * the timing controller on timing aware tests or by throttling rate of calling tests methods on non-timing aware - * tests. - * @todo Make acknowledege mode a test option. - * @todo Make the message listener a static for all replies to be sent to? It won't be any more of a bottle neck than - * having one per PingPongProducer, as will synchronize on message correlation id, allowing threads to process - * messages concurrently for different ids. Needs to be static so that when using a chained message listener and - * shared destinations between multiple PPPs, it gets notified about all replies, not just those that happen to - * be picked up by the PPP that it is atteched to. - * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock - * pair. Obtian read lock on all messages, before decrementing the message count. At the end of the on message - * method add a block that obtains the write lock for the very last message, releases any waiting producer. Means - * that the last message waits until all other messages have been handled before releasing producers but allows - * messages to be processed concurrently, unlike the current synchronized block. - * @todo Need to multiply up the number of expected messages for pubsub tests as each can be received by many consumers? + * @todo Make the message listener a static for all replies to be sent to? It won't be any more of a bottle neck than having + * one per PingPongProducer, as will synchronize on message correlation id, allowing threads to process messages + * concurrently for different ids. Needs to be static so that when using a chained message listener and shared + * destinations between multiple PPPs, it gets notified about all replies, not just those that happen to be picked up + * by the PPP that it is atteched to. + * + * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock pair. + * Obtian read lock on all messages, before decrementing the message count. At the end of the on message method add a + * block that obtains the write lock for the very last message, releases any waiting producer. Means that the last + * message waits until all other messages have been handled before releasing producers but allows messages to be + * processed concurrently, unlike the current synchronized block. + * + * @todo Get rid of pauses between batches, it will impact the timing statistics, and generate meanigless timings. + * Instead make mina use a bounded blocking buffer, or other form of back pressure, to stop data being written + * faster than it can be sent. */ public class PingPongProducer implements Runnable, MessageListener, ExceptionListener { private static final Logger _logger = Logger.getLogger(PingPongProducer.class); - /** - * Holds the name of the property to get the test message size from. - */ - public static final String MESSAGE_SIZE_PROPNAME = "messagesize"; + /** Holds the name of the property to get the test message size from. */ + public static final String MESSAGE_SIZE_PROPNAME = "messageSize"; - /** - * Holds the name of the property to get the ping queue name from. - */ - public static final String PING_QUEUE_NAME_PROPNAME = "destinationname"; + /** Used to set up a default message size. */ + public static final int MESSAGE_SIZE_DEAFULT = 0; - /** - * Holds the name of the property to get the test delivery mode from. - */ - public static final String PERSISTENT_MODE_PROPNAME = "persistent"; + /** Holds the name of the property to get the ping queue name from. */ + public static final String PING_QUEUE_NAME_PROPNAME = "destinationName"; - /** - * Holds the name of the property to get the test transactional mode from. - */ - public static final String TRANSACTED_PROPNAME = "transacted"; + /** Holds the name of the default destination to send pings on. */ + public static final String PING_QUEUE_NAME_DEFAULT = "ping"; - /** - * Holds the name of the property to get the test broker url from. - */ - public static final String BROKER_PROPNAME = "broker"; + /** Holds the name of the property to get the test delivery mode from. */ + public static final String PERSISTENT_MODE_PROPNAME = "persistent"; - /** - * Holds the name of the property to get the test broker virtual path. - */ - public static final String VIRTUAL_PATH_PROPNAME = "virtualPath"; + /** Holds the message delivery mode to use for the test. */ + public static final boolean PERSISTENT_MODE_DEFAULT = false; - /** - * Holds the name of the property to get the message rate from. - */ - public static final String RATE_PROPNAME = "rate"; + /** Holds the name of the property to get the test transactional mode from. */ + public static final String TRANSACTED_PROPNAME = "transacted"; - public static final String VERBOSE_OUTPUT_PROPNAME = "verbose"; + /** Holds the transactional mode to use for the test. */ + public static final boolean TRANSACTED_DEFAULT = false; - /** - * Holds the true or false depending on wether it is P2P test or PubSub - */ - public static final String IS_PUBSUB_PROPNAME = "pubsub"; + /** Holds the name of the property to get the test broker url from. */ + public static final String BROKER_PROPNAME = "broker"; - public static final String FAIL_AFTER_COMMIT_PROPNAME = "FailAfterCommit"; + /** Holds the default broker url for the test. */ + public static final String BROKER_DEFAULT = "tcp://localhost:5672"; - public static final String FAIL_BEFORE_COMMIT_PROPNAME = "FailBeforeCommit"; + /** Holds the name of the property to get the test broker virtual path. */ + public static final String VIRTUAL_HOST_PROPNAME = "virtualHost"; - public static final String FAIL_AFTER_SEND_PROPNAME = "FailAfterSend"; + /** Holds the default virtual path for the test. */ + public static final String VIRTUAL_HOST_DEFAULT = ""; - public static final String FAIL_BEFORE_SEND_PROPNAME = "FailBeforeSend"; + /** Holds the name of the property to get the message rate from. */ + public static final String RATE_PROPNAME = "rate"; - public static final String FAIL_ONCE_PROPNAME = "FailOnce"; + /** Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. */ + public static final int RATE_DEFAULT = 0; - public static final String USERNAME_PROPNAME = "username"; + /** Holds the name of the property to get the verbose mode proeprty from. */ + public static final String VERBOSE_PROPNAME = "verbose"; - public static final String PASSWORD_PROPNAME = "password"; + /** Holds the default verbose mode. */ + public static final boolean VERBOSE_DEFAULT = false; - public static final String SELECTOR_PROPNAME = "selector"; + /** Holds the name of the property to get the p2p or pub/sub messaging mode from. */ + public static final String PUBSUB_PROPNAME = "pubsub"; - public static final String PING_DESTINATION_COUNT_PROPNAME = "destinationscount"; + /** Holds the pub/sub mode default, true means ping a topic, false means ping a queue. */ + public static final boolean PUBSUB_DEFAULT = false; - /** - * Holds the name of the property to get the waiting timeout for response messages. - */ - public static final String TIMEOUT_PROPNAME = "timeout"; + /** Holds the name of the property to get the fail after commit flag from. */ + public static final String FAIL_AFTER_COMMIT_PROPNAME = "failAfterCommit"; - public static final String COMMIT_BATCH_SIZE_PROPNAME = "CommitBatchSize"; + /** Holds the default failover after commit test flag. */ + public static final String FAIL_AFTER_COMMIT_DEFAULT = "false"; - public static final String UNIQUE_PROPNAME = "uniqueDests"; + /** Holds the name of the proeprty to get the fail before commit flag from. */ + public static final String FAIL_BEFORE_COMMIT_PROPNAME = "failBeforeCommit"; - public static final String ACK_MODE_PROPNAME = "ackMode"; + /** Holds the default failover before commit test flag. */ + public static final String FAIL_BEFORE_COMMIT_DEFAULT = "false"; - public static final String PAUSE_AFTER_BATCH_PROPNAME = "pausetimeAfterEachBatch"; - - /** - * Used to set up a default message size. - */ - public static final int DEFAULT_MESSAGE_SIZE = 0; + /** Holds the name of the proeprty to get the fail after send flag from. */ + public static final String FAIL_AFTER_SEND_PROPNAME = "failAfterSend"; - /** - * Holds the name of the default destination to send pings on. - */ - public static final String DEFAULT_PING_DESTINATION_NAME = "ping"; + /** Holds the default failover after send test flag. */ + public static final String FAIL_AFTER_SEND_DEFAULT = "false"; - /** - * Defines the default number of destinations to ping. - */ - public static final int DEFAULT_DESTINATION_COUNT = 1; + /** Holds the name of the property to get the fail before send flag from. */ + public static final String FAIL_BEFORE_SEND_PROPNAME = "failBeforeSend"; - /** - * Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. - */ - public static final int DEFAULT_RATE = 0; + /** Holds the default failover before send test flag. */ + public static final String FAIL_BEFORE_SEND_DEFAULT = "false"; - /** - * Defines the default wait between pings. - */ - public static final long DEFAULT_SLEEP_TIME = 250; + /** Holds the name of the property to get the fail once flag from. */ + public static final String FAIL_ONCE_PROPNAME = "failOnce"; - /** - * Default time to wait before assuming that a ping has timed out. - */ - public static final long DEFAULT_TIMEOUT = 30000; + /** The default failover once flag, true means only do one failover, false means failover on every commit cycle. */ + public static final String FAIL_ONCE_DEFAULT = "true"; - /** - * Defines the default number of pings to send in each transaction when running transactionally. - */ - public static final int DEFAULT_TX_BATCH_SIZE = 100; + /** Holds the name of the property to get the broker access username from. */ + public static final String USERNAME_PROPNAME = "username"; - /** - * Defines the default prefetch size to use when consuming messages. - */ - public static final int DEFAULT_PREFETCH = 100; + /** Holds the default broker log on username. */ + public static final String USERNAME_DEFAULT = "guest"; - /** - * Defines the default value of the no local flag to use when consuming messages. - */ - public static final boolean DEFAULT_NO_LOCAL = false; + /** Holds the name of the property to get the broker access password from. */ + public static final String PASSWORD_PROPNAME = "password"; - /** - * Defines the default value of the exclusive flag to use when consuming messages. - */ - public static final boolean DEFAULT_EXCLUSIVE = false; + /** Holds the default broker log on password. */ + public static final String PASSWORD_DEFAULT = "guest"; - /** - * Holds the message delivery mode to use for the test. - */ - public static final boolean DEFAULT_PERSISTENT_MODE = false; + /** Holds the name of the proeprty to get the. */ + public static final String SELECTOR_PROPNAME = "selector"; - /** - * Holds the transactional mode to use for the test. - */ - public static final boolean DEFAULT_TRANSACTED = false; + /** Holds the default message selector. */ + public static final String SELECTOR_DEFAULT = null; - /** - * Holds the default broker url for the test. - */ - public static final String DEFAULT_BROKER = "tcp://localhost:5672"; + /** Holds the name of the proeprty to get the destination count from. */ + public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; - /** - * Holds the default virtual path for the test. - */ - public static final String DEFAULT_VIRTUAL_PATH = "test"; + /** Defines the default number of destinations to ping. */ + public static final int DESTINATION_COUNT_DEFAULT = 1; - /** - * Holds the pub/sub mode default, true means ping a topic, false means ping a queue. - */ - public static final boolean DEFAULT_PUBSUB = false; + /** Holds the name of the property to get the waiting timeout for response messages. */ + public static final String TIMEOUT_PROPNAME = "timeout"; - /** - * Holds the default broker log on username. - */ - public static final String DEFAULT_USERNAME = "guest"; + /** Default time to wait before assuming that a ping has timed out. */ + public static final long TIMEOUT_DEFAULT = 30000; - /** - * Holds the default broker log on password. - */ - public static final String DEFAULT_PASSWORD = "guest"; + /** Holds the name of the property to get the commit batch size from. */ + public static final String TX_BATCH_SIZE_PROPNAME = "commitBatchSize"; - /** - * Holds the default message selector. - */ - public static final String DEFAULT_SELECTOR = null; + /** Defines the default number of pings to send in each transaction when running transactionally. */ + public static final int TX_BATCH_SIZE_DEFAULT = 1; - /** - * Holds the default failover after commit test flag. - */ - public static final String DEFAULT_FAIL_AFTER_COMMIT = "false"; + /** Holds the name of the property to get the unique destinations flag from. */ + public static final String UNIQUE_DESTS_PROPNAME = "uniqueDests"; - /** - * Holds the default failover before commit test flag. - */ - public static final String DEFAULT_FAIL_BEFORE_COMMIT = "false"; + /** Defines the default value for the unique destinations property. */ + public static final boolean UNIQUE_DESTS_DEFAULT = true; - /** - * Holds the default failover after send test flag. - */ - public static final String DEFAULT_FAIL_AFTER_SEND = "false"; + /** Holds the name of the proeprty to get the message acknowledgement mode from. */ + public static final String ACK_MODE_PROPNAME = "ackMode"; - /** - * Holds the default failover before send test flag. - */ - public static final String DEFAULT_FAIL_BEFORE_SEND = "false"; + /** Defines the default message acknowledgement mode. */ + public static final int ACK_MODE_DEFAULT = Session.NO_ACKNOWLEDGE; - /** - * Holds the default failover only once flag, true means only do one failover, false means failover on every commit cycle. - */ - public static final String DEFAULT_FAIL_ONCE = "true"; + /** Holds the name of the property to get the pause between batches property from. */ + public static final String PAUSE_AFTER_BATCH_PROPNAME = "pauseBatch"; - /** - * Holds the default verbose mode. - */ - public static final boolean DEFAULT_VERBOSE = false; + /** Defines the default time in milliseconds to wait between commit batches. */ + public static final long PAUSE_AFTER_BATCH_DEFAULT = 0L; - public static final boolean DEFAULT_UNIQUE = true; + /** Defines the default prefetch size to use when consuming messages. */ + public static final int PREFETCH_DEFAULT = 100; - public static final int DEFAULT_ACK_MODE = Session.NO_ACKNOWLEDGE; + /** Defines the default value of the no local flag to use when consuming messages. */ + public static final boolean NO_LOCAL_DEFAULT = false; - /** - * Holds the name of the property to store nanosecond timestamps in ping messages with. - */ + /** Defines the default value of the exclusive flag to use when consuming messages. */ + public static final boolean EXCLUSIVE_DEFAULT = false; + + /** Holds the name of the property to store nanosecond timestamps in ping messages with. */ public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp"; - /** - * A source for providing sequential unique correlation ids. These will be unique within the same JVM. - */ + /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); /** - * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross - * multiple ping producers on the same JVM. + * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross multiple + * ping producers on the same JVM. */ - /*private static Map trafficLights = - Collections.synchronizedMap(new HashMap());*/ private static Map perCorrelationIds = - Collections.synchronizedMap(new HashMap()); + Collections.synchronizedMap(new HashMap()); - /** - * A convenient formatter to use when time stamping output. - */ + /** A convenient formatter to use when time stamping output. */ protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); /** @@ -322,52 +291,35 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ protected static AtomicInteger _queueJVMSequenceID = new AtomicInteger(); - /** - * Destination where the response messages will arrive. - */ + /** Holds the destination where the response messages will arrive. */ private Destination _replyDestination; - /** - * Determines whether this producer sends persistent messages. - */ + /** Determines whether this producer sends persistent messages. */ protected boolean _persistent; + /** Holds the acknowledgement mode used for sending and receiving messages. */ private int _ackMode = Session.NO_ACKNOWLEDGE; - /** - * Determines what size of messages this producer sends. - */ + /** Determines what size of messages this producer sends. */ protected int _messageSize; - /** - * Used to indicate that the ping loop should print out whenever it pings. - */ - protected boolean _verbose = false; + /** Used to indicate that the ping loop should print out whenever it pings. */ + protected boolean _verbose = VERBOSE_DEFAULT; - /** - * Holds the session on which ping replies are received. - */ + /** Holds the session on which ping replies are received. */ protected Session _consumerSession; - /** - * Used to restrict the sending rate to a specified limit. - */ + /** Used to restrict the sending rate to a specified limit. */ private Throttle _rateLimiter = null; - /** - * Holds a message listener that this message listener chains all its messages to. - */ + /** Holds a message listener that this message listener chains all its messages to. */ private ChainedMessageListener _chainedMessageListener = null; - /** - * Flag used to indicate if this is a point to point or pub/sub ping client. - */ - protected boolean _isPubSub = false; + /** Flag used to indicate if this is a point to point or pub/sub ping client. */ + protected boolean _isPubSub = PUBSUB_DEFAULT; - /** - * Flag used to indicate if the destinations should be unique client. - */ - protected static boolean _isUnique = false; + /** Flag used to indicate if the destinations should be unique client. */ + protected static boolean _isUnique = UNIQUE_DESTS_DEFAULT; /** * This id generator is used to generates ids that are only unique within this pinger. Creating multiple pingers @@ -375,96 +327,79 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ protected AtomicInteger _queueSharedId = new AtomicInteger(); - /** - * Used to tell the ping loop when to terminate, it only runs while this is true. - */ + /** Used to tell the ping loop when to terminate, it only runs while this is true. */ protected boolean _publish = true; - /** - * Holds the connection to the broker. - */ + /** Holds the connection to the broker. */ private Connection _connection; - /** - * Holds the producer session, needed to create ping messages. - */ + /** Holds the producer session, needed to create ping messages. */ private Session _producerSession; - /** - * Holds the set of destiniations that this ping producer pings. - */ + /** Holds the set of destinations that this ping producer pings. */ protected List _pingDestinations = new ArrayList(); - /** - * Holds the message producer to send the pings through. - */ + /** Holds the message producer to send the pings through. */ protected MessageProducer _producer; - /** - * Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. - */ + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ protected boolean _failBeforeCommit = false; - /** - * Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. - */ + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ protected boolean _failAfterCommit = false; - /** - * Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. - */ + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ protected boolean _failBeforeSend = false; - /** - * Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. - */ + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ protected boolean _failAfterSend = false; - /** - * Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. - */ + /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ protected boolean _failOnce = true; - /** - * Holds the number of sends that should be performed in every transaction when using transactions. - */ - protected int _txBatchSize = 1; + /** Holds the number of sends that should be performed in every transaction when using transactions. */ + protected int _txBatchSize = TX_BATCH_SIZE_DEFAULT; - private static long _pausetimeAfterEachBatch = 0; + /** Holds the wait time to insert between every batch of messages committed. */ + private static long _pauseBatch = PAUSE_AFTER_BATCH_DEFAULT; /** - * Holds the number of consumers that will be attached to each topic. - * Each pings will result in a reply from each of the attached clients + * Holds the number of consumers that will be attached to each topic. Each pings will result in a reply from each of the + * attached clients */ static int _consumersPerTopic = 1; /** - * Creates a ping producer with the specified parameters, of which there are many. See their individual comments - * for details. This constructor creates a connection to the broker and creates producer and consumer sessions on it, - * to send and recieve its pings and replies on. The other options are kept, and control how this pinger behaves. + * Creates a ping producer with the specified parameters, of which there are many. See their individual comments for + * details. This constructor creates a connection to the broker and creates producer and consumer sessions on it, to send + * and recieve its pings and replies on. The other options are kept, and control how this pinger behaves. + * + * @param brokerDetails The URL of the broker to send pings to. + * @param username The username to log onto the broker with. + * @param password The password to log onto the broker with. + * @param virtualpath The virtual host name to use on the broker. + * @param destinationName The name (or root where multiple destinations are used) of the desitination to send pings to. + * @param selector The selector to filter replies with. + * @param transacted Indicates whether or not pings are sent and received in transactions. + * @param persistent Indicates whether pings are sent using peristent delivery. + * @param messageSize Specifies the size of ping messages to send. + * @param verbose Indicates that information should be printed to the console on every ping. + * @param afterCommit Indicates that the user should be promted to terminate a broker after commits to test + * failover. + * @param beforeCommit Indicates that the user should be promted to terminate a broker before commits to test + * failover. + * @param afterSend Indicates that the user should be promted to terminate a broker after sends to test failover. + * @param beforeSend Indicates that the user should be promted to terminate a broker before sends to test + * failover. + * @param failOnce Indicates that the failover testing behaviour should only happen on the first commit, not + * all. + * @param txBatchSize Specifies the number of pings to send in each transaction. + * @param noOfDestinations The number of destinations to ping. Must be 1 or more. + * @param rate Specified the number of pings per second to send. Setting this to 0 means send as fast as + * possible, with no rate restriction. + * @param pubsub True to ping topics, false to ping queues. + * @param unique True to use unique destinations for each ping pong producer, false to share. * - * @param brokerDetails The URL of the broker to send pings to. - * @param username The username to log onto the broker with. - * @param password The password to log onto the broker with. - * @param virtualpath The virtual host name to use on the broker. - * @param destinationName The name (or root where multiple destinations are used) of the desitination to send - * pings to. - * @param selector The selector to filter replies with. - * @param transacted Indicates whether or not pings are sent and received in transactions. - * @param persistent Indicates whether pings are sent using peristent delivery. - * @param messageSize Specifies the size of ping messages to send. - * @param verbose Indicates that information should be printed to the console on every ping. - * @param afterCommit Indicates that the user should be promted to terminate a broker after commits to test failover. - * @param beforeCommit Indicates that the user should be promted to terminate a broker before commits to test failover. - * @param afterSend Indicates that the user should be promted to terminate a broker after sends to test failover. - * @param beforeSend Indicates that the user should be promted to terminate a broker before sends to test failover. - * @param failOnce Indicates that the failover testing behaviour should only happen on the first commit, not all. - * @param txBatchSize Specifies the number of pings to send in each transaction. - * @param noOfDestinations The number of destinations to ping. Must be 1 or more. - * @param rate Specified the number of pings per second to send. Setting this to 0 means send as fast as - * possible, with no rate restriction. - * @param pubsub True to ping topics, false to ping queues. - * @param unique True to use unique destinations for each ping pong producer, false to share. * @throws Exception Any exceptions are allowed to fall through. */ public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, @@ -481,8 +416,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis + afterCommit + ", boolean beforeCommit = " + beforeCommit + ", boolean afterSend = " + afterSend + ", boolean beforeSend = " + beforeSend + ", boolean failOnce = " + failOnce + ", int txBatchSize = " + txBatchSize + ", int noOfDestinations = " + noOfDestinations + ", int rate = " + rate - + ", boolean pubsub = " + pubsub + ", boolean unique = " + unique - + ", ackMode = " + ackMode + "): called"); + + ", boolean pubsub = " + pubsub + ", boolean unique = " + unique + ", ackMode = " + ackMode + + "): called"); // Keep all the relevant options. _persistent = persistent; @@ -496,12 +431,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _txBatchSize = txBatchSize; _isPubSub = pubsub; _isUnique = unique; - _pausetimeAfterEachBatch = pause; + _pauseBatch = pause; + if (ackMode != 0) { _ackMode = ackMode; } - + // Check that one or more destinations were specified. if (noOfDestinations < 1) { @@ -535,10 +471,11 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Starts a ping-pong loop running from the command line. The bounce back client {@link PingPongBouncer} also needs - * to be started to bounce the pings back again. + * Starts a ping-pong loop running from the command line. The bounce back client {@link PingPongBouncer} also needs to be + * started to bounce the pings back again. + * + * @param args The command line arguments. * - * @param args The command line arguments. * @throws Exception When something went wrong with the test */ public static void main(String[] args) throws Exception @@ -549,28 +486,27 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis if (args.length == 0) { _logger.info("Running test with default values..."); - //usage(); - //System.exit(0); + // usage(); + // System.exit(0); } String brokerDetails = config.getHost() + ":" + config.getPort(); - String virtualpath = DEFAULT_VIRTUAL_PATH; - String selector = (config.getSelector() == null) ? DEFAULT_SELECTOR : config.getSelector(); + String virtualpath = VIRTUAL_HOST_DEFAULT; + String selector = (config.getSelector() == null) ? SELECTOR_DEFAULT : config.getSelector(); boolean verbose = true; boolean transacted = config.isTransacted(); boolean persistent = config.usePersistentMessages(); - int messageSize = (config.getPayload() != 0) ? config.getPayload() : DEFAULT_MESSAGE_SIZE; - int messageCount = config.getMessages(); - int destCount = (config.getDestinationsCount() != 0) ? config.getDestinationsCount() : DEFAULT_DESTINATION_COUNT; - int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : DEFAULT_TX_BATCH_SIZE; - int rate = (config.getRate() != 0) ? config.getRate() : DEFAULT_RATE; + int messageSize = (config.getPayload() != 0) ? config.getPayload() : MESSAGE_SIZE_DEAFULT; + // int messageCount = config.getMessages(); + int destCount = (config.getDestinationsCount() != 0) ? config.getDestinationsCount() : DESTINATION_COUNT_DEFAULT; + int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : TX_BATCH_SIZE_DEFAULT; + int rate = (config.getRate() != 0) ? config.getRate() : RATE_DEFAULT; boolean pubsub = config.isPubSub(); - long timeout = (config.getTimeout() != 0) ? config.getTimeout() : DEFAULT_TIMEOUT; String destName = config.getDestination(); if (destName == null) { - destName = DEFAULT_PING_DESTINATION_NAME; + destName = PING_QUEUE_NAME_DEFAULT; } boolean afterCommit = false; @@ -583,7 +519,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { if (arg.startsWith("failover:")) { - //failover:: | failover:once + // failover:: | failover:once String[] parts = arg.split(":"); if (parts.length == 3) { @@ -613,9 +549,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Create a ping producer to handle the request/wait/reply cycle. PingPongProducer pingProducer = - new PingPongProducer(brokerDetails, DEFAULT_USERNAME, DEFAULT_PASSWORD, virtualpath, destName, selector, - transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, - beforeSend, failOnce, batchSize, destCount, rate, pubsub, false, 0, 0); + new PingPongProducer(brokerDetails, USERNAME_DEFAULT, PASSWORD_DEFAULT, virtualpath, destName, selector, + transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, + beforeSend, failOnce, batchSize, destCount, rate, pubsub, false, 0, 0); pingProducer.getConnection().start(); @@ -625,19 +561,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. pingProducer.getConnection().setExceptionListener(pingProducer); - // If messageount is 0, then continue sending - if (messageCount == 0) - { - // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. - Thread pingThread = new Thread(pingProducer); - pingThread.start(); - pingThread.join(); - } - else - { - pingProducer.ping(messageCount, timeout); - } - pingProducer.close(); + // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. + Thread pingThread = new Thread(pingProducer); + pingThread.run(); + pingThread.join(); } /** @@ -655,14 +582,14 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } catch (InterruptedException ie) { - //ignore + // ignore } } } /** - * Gets all the reply destinations (to listen for replies on). In this case this will just be the single reply - * to destination of this pinger. + * Gets all the reply destinations (to listen for replies on). In this case this will just be the single reply to + * destination of this pinger. * * @return The single reply to destination of this pinger, wrapped in a list. */ @@ -677,8 +604,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Creates the producer to send the pings on. This is created without a default destination. Its persistent delivery - * flag is set accoring the ping producer creation options. + * Creates the producer to send the pings on. This is created without a default destination. Its persistent delivery flag + * is set accoring the ping producer creation options. * * @throws JMSException Any JMSExceptions are allowed to fall through. */ @@ -687,23 +614,24 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _logger.debug("public void createProducer(): called"); _producer = (MessageProducer) _producerSession.createProducer(null); - //_producer.setDisableMessageTimestamp(true); + // _producer.setDisableMessageTimestamp(true); _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); } /** - * Creates consumers for the specified number of destinations. The destinations themselves are also created by - * this method. + * Creates consumers for the specified number of destinations. The destinations themselves are also created by this + * method. + * + * @param noOfDestinations The number of destinations to create consumers for. + * @param selector The message selector to filter the consumers with. + * @param rootName The root of the name, or actual name if only one is being created. + * @param unique true to make the destinations unique to this pinger, false to share the + * numbering with all pingers on the same JVM. * - * @param noOfDestinations The number of destinations to create consumers for. - * @param selector The message selector to filter the consumers with. - * @param rootName The root of the name, or actual name if only one is being created. - * @param unique true to make the destinations unique to this pinger, false to share - * the numbering with all pingers on the same JVM. * @throws JMSException Any JMSExceptions are allowed to fall through. */ public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique) - throws JMSException + throws JMSException { _logger.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " + selector + ", String rootName = " + rootName + ", boolean unique = " @@ -747,9 +675,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Stores the received message in the replies map, then resets the boolean latch that a thread waiting for a - * correlating reply may be waiting on. This is only done if the reply has a correlation id that is expected - * in the replies map. + * Stores the received message in the replies map, then resets the boolean latch that a thread waiting for a correlating + * reply may be waiting on. This is only done if the reply has a correlation id that is expected in the replies map. * * @param message The received message. */ @@ -796,13 +723,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis if ((remainingCount % _txBatchSize) == 0) { commitTx(_consumerSession); - if (!_consumerSession.getTransacted() && - _consumerSession.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) - { - ((AMQSession)_consumerSession).acknowledge(); - } } - + // Forward the message and remaining count to any interested chained message listener. if (_chainedMessageListener != null) { @@ -843,15 +765,17 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out - * before a reply arrives, then a null reply is returned from this method. This method generates a new unqiue - * correlation id for the messages. + * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out before a + * reply arrives, then a null reply is returned from this method. This method generates a new unqiue correlation id for + * the messages. + * + * @param message The message to send. + * @param numPings The number of ping messages to send. + * @param timeout The timeout in milliseconds. + * + * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait for + * all prematurely. * - * @param message The message to send. - * @param numPings The number of ping messages to send. - * @param timeout The timeout in milliseconds. - * @return The number of replies received. This may be less than the number sent if the timeout terminated the - * wait for all prematurely. * @throws JMSException All underlying JMSExceptions are allowed to fall through. * @throws InterruptedException When interrupted by a timeout. */ @@ -867,27 +791,29 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } public int pingAndWaitForReply(int numPings, long timeout, String messageCorrelationId) - throws JMSException, InterruptedException + throws JMSException, InterruptedException { - return pingAndWaitForReply(null, numPings, timeout, messageCorrelationId); + return pingAndWaitForReply(null, numPings, timeout, messageCorrelationId); } /** - * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out - * before a reply arrives, then a null reply is returned from this method. This method allows the caller to specify - * the correlation id. + * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out before a + * reply arrives, then a null reply is returned from this method. This method allows the caller to specify the + * correlation id. + * + * @param message The message to send. + * @param numPings The number of ping messages to send. + * @param timeout The timeout in milliseconds. + * @param messageCorrelationId The message correlation id. + * + * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait for + * all prematurely. * - * @param message The message to send. - * @param numPings The number of ping messages to send. - * @param timeout The timeout in milliseconds. - * @param messageCorrelationId The message correlation id. - * @return The number of replies received. This may be less than the number sent if the timeout terminated the - * wait for all prematurely. * @throws JMSException All underlying JMSExceptions are allowed to fall through. * @throws InterruptedException When interrupted by a timeout */ public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) - throws JMSException, InterruptedException + throws JMSException, InterruptedException { _logger.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called"); @@ -964,9 +890,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** * Sends the specified number of ping messages and does not wait for correlating replies. * - * @param message The message to send. - * @param numPings The number of pings to send. - * @param messageCorrelationId A correlation id to place on all messages sent. + * @param message The message to send. + * @param numPings The number of pings to send. + * @param messageCorrelationId A correlation id to place on all messages sent. + * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException @@ -996,7 +923,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); // Round robin the destinations as the messages are sent. - //return _destinationCount; + // return _destinationCount; sendMessage(_pingDestinations.get(i % _pingDestinations.size()), message); // Apply message rate throttling if a rate limit has been set up. @@ -1010,11 +937,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { commitTx(_producerSession); committed = true; + /* This pause is required for some cases. eg in load testing when sessions are non-transacted the Mina IO layer can't clear the cache in time. So this pause gives enough time for mina to clear the cache (without this mina throws OutOfMemoryError). pause() will check if time is != 0 - */ - pause(_pausetimeAfterEachBatch); + */ + pause(_pauseBatch); } // Spew out per message timings on every message sonly in verbose mode. @@ -1033,9 +961,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * The ping implementation. This sends out pings waits for replies and inserts short pauses in between each. + * The ping loop implementation. This sends out pings waits for replies and inserts short pauses in between each. */ - public void ping(int pingCount, long timeout) + public void pingLoop() { try { @@ -1044,10 +972,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); // Send the message and wait for a reply. - pingAndWaitForReply(msg, pingCount, timeout); - - // Introduce a short pause if desired. - pause(DEFAULT_SLEEP_TIME); + pingAndWaitForReply(msg, TX_BATCH_SIZE_DEFAULT, TIMEOUT_DEFAULT); } catch (JMSException e) { @@ -1061,19 +986,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } } - public void ping() - { - ping(DEFAULT_TX_BATCH_SIZE, DEFAULT_TIMEOUT); - } - public Destination getReplyDestination() { return getReplyDestinations().get(0); } /** - * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set - * here. + * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set here. * * @param messageListener The chained message listener. */ @@ -1093,10 +1012,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** * Generates a test message of the specified size, with the specified reply-to destination and persistence flag. * - * @param replyQueue The reply-to destination for the message. - * @param messageSize The desired size of the message in bytes. - * @param persistent true if the message should use persistent delivery, false otherwise. + * @param replyQueue The reply-to destination for the message. + * @param messageSize The desired size of the message in bytes. + * @param persistent true if the message should use persistent delivery, false otherwise. + * * @return A freshly generated test message. + * * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. */ public ObjectMessage getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException @@ -1110,8 +1031,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this - * flag has been cleared. + * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this flag has + * been cleared. */ public void stop() { @@ -1126,13 +1047,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Keep running until the publish flag is cleared. while (_publish) { - ping(); + pingLoop(); } } /** - * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the - * connection, this clears the publish flag which in turn will halt the ping loop. + * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the connection, + * this clears the publish flag which in turn will halt the ping loop. * * @param e The exception that triggered this callback method. */ @@ -1143,20 +1064,20 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered - * with the runtime system as a shutdown hook. + * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered with + * the runtime system as a shutdown hook. * * @return A shutdown hook for the ping loop. */ public Thread getShutdownHook() { return new Thread(new Runnable() - { - public void run() { - stop(); - } - }); + public void run() + { + stop(); + } + }); } /** @@ -1172,8 +1093,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** * Creates consumers for the specified destinations and registers this pinger to listen to their messages. * - * @param destinations The destinations to listen to. - * @param selector A selector to filter the messages with. + * @param destinations The destinations to listen to. + * @param selector A selector to filter the messages with. + * * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through. */ public void createReplyConsumers(Collection destinations, String selector) throws JMSException @@ -1185,8 +1107,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { // Create a consumer for the destination and set this pinger to listen to its messages. MessageConsumer consumer = - _consumerSession.createConsumer(destination, DEFAULT_PREFETCH, DEFAULT_NO_LOCAL, DEFAULT_EXCLUSIVE, - selector); + _consumerSession.createConsumer(destination, PREFETCH_DEFAULT, NO_LOCAL_DEFAULT, EXCLUSIVE_DEFAULT, + selector); consumer.setMessageListener(this); } } @@ -1207,22 +1129,23 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Convenience method to commit the transaction on the specified session. If the session to commit on is not - * a transactional session, this method does nothing (unless the failover after send flag is set). - *

    - *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit - * is applied. This flag applies whether the pinger is transactional or not. - *

    - *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the - * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker - * after the commit is applied. These flags will only apply if using a transactional pinger. + * Convenience method to commit the transaction on the specified session. If the session to commit on is not a + * transactional session, this method does nothing (unless the failover after send flag is set). + * + *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit is + * applied. This flag applies whether the pinger is transactional or not. + * + *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the commit is + * applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker after the commit + * is applied. These flags will only apply if using a transactional pinger. + * + * @param session The session to commit * - * @param session The session to commit * @throws javax.jms.JMSException If the commit fails and then the rollback fails. - *

    - * //todo @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit - * method, because commits only apply to transactional pingers, but fail after send applied to transactional - * and non-transactional alike. + * + * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit + * method, because commits only apply to transactional pingers, but fail after send applied to transactional and + * non-transactional alike. */ protected void commitTx(Session session) throws JMSException { @@ -1258,7 +1181,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis long l = System.currentTimeMillis(); session.commit(); - _logger.debug("Time taken to commit :" + (System.currentTimeMillis() - l) + " ms" ); + _logger.debug("Time taken to commit :" + (System.currentTimeMillis() - l) + " ms"); if (_failAfterCommit) { @@ -1300,11 +1223,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Sends the message to the specified destination. If the destination is null, it gets sent to the default destination - * of the ping producer. If an explicit destination is set, this overrides the default. + * Sends the message to the specified destination. If the destination is null, it gets sent to the default destination of + * the ping producer. If an explicit destination is set, this overrides the default. + * + * @param destination The destination to send to. + * @param message The message to send. * - * @param destination The destination to send to. - * @param message The message to send. * @throws javax.jms.JMSException All underlying JMSExceptions are allowed to fall through. */ protected void sendMessage(Destination destination, Message message) throws JMSException @@ -1331,8 +1255,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Prompts the user to terminate the broker, in order to test failover functionality. This method will block - * until the user supplied some input on the terminal. + * Prompts the user to terminate the broker, in order to test failover functionality. This method will block until the + * user supplied some input on the terminal. */ protected void doFailover() { @@ -1343,7 +1267,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } catch (IOException e) { - //ignore + // ignore } System.out.println("Continuing."); @@ -1364,16 +1288,15 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis return numpings * getConsumersPerTopic(); } - /** - * Defines a chained message listener interface that can be attached to this pinger. Whenever this pinger's - * {@link PingPongProducer#onMessage} method is called, the chained listener set through the - * {@link PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected - * count of messages with that correlation id. - *

    - * Provided only one pinger is producing messages with that correlation id, the chained listener will always be - * given unique message counts. It will always be called while the producer waiting for all messages to arrive is - * still blocked. + * Defines a chained message listener interface that can be attached to this pinger. Whenever this pinger's {@link + * PingPongProducer#onMessage} method is called, the chained listener set through the {@link + * PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected count of messages + * with that correlation id. + * + *

    Provided only one pinger is producing messages with that correlation id, the chained listener will always be given + * unique message counts. It will always be called while the producer waiting for all messages to arrive is still + * blocked. */ public static interface ChainedMessageListener { @@ -1381,19 +1304,15 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Holds information on each correlation id. The countdown latch, the current timeout timer... More stuff to be - * added to this: read/write lock to make onMessage more concurrent as described in class header comment. + * Holds information on each correlation id. The countdown latch, the current timeout timer... More stuff to be added to + * this: read/write lock to make onMessage more concurrent as described in class header comment. */ protected static class PerCorrelationId { - /** - * Holds a countdown on number of expected messages. - */ + /** Holds a countdown on number of expected messages. */ CountDownLatch trafficLight; - /** - * Holds the last timestamp that the timeout was reset to. - */ + /** Holds the last timestamp that the timeout was reset to. */ Long timeOutStart; } } -- cgit v1.2.1 From ab77fcc2ed974e8d4ac2a56be62cc2cb3f8e2c11 Mon Sep 17 00:00:00 2001 From: Bhupendra Bhusman Bhardwaj Date: Tue, 27 Mar 2007 09:07:30 +0000 Subject: merged from M2 (r521792:522567) QPID-408 QPID-421 QPID-428 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@522821 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/requestreply/PingPongProducer.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 2a3aff4692..c6a69807a3 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -39,6 +39,7 @@ import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQNoConsumersException; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.jms.MessageProducer; @@ -723,6 +724,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis if ((remainingCount % _txBatchSize) == 0) { commitTx(_consumerSession); + if (!_consumerSession.getTransacted() && + _consumerSession.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) + { + // Acknowledge the messages when the session is not transacted but client_ack + ((AMQSession) _consumerSession).acknowledge(); + } } // Forward the message and remaining count to any interested chained message listener. -- cgit v1.2.1 From 6aaec799e2dd38f39601fe5fe458cadf3834aae8 Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 5 Apr 2007 11:47:50 +0000 Subject: Merged revisions 522994-523245 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r522994 | rgreig | 2007-03-27 17:48:23 +0100 (Tue, 27 Mar 2007) | 1 line Test added for durability of messages under broker failure. ........ r523245 | rgreig | 2007-03-28 10:30:49 +0100 (Wed, 28 Mar 2007) | 1 line Reversed accidental replacing of the word 'initialize' in comments to 'establishConnection' through a method refactoring. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@525800 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/ping/PingClient.java | 56 +- .../org/apache/qpid/ping/PingDurableClient.java | 389 +++++++++ .../apache/qpid/requestreply/PingPongProducer.java | 930 +++++++++++---------- 3 files changed, 898 insertions(+), 477 deletions(-) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java index 013bda5927..e3b0249ed3 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java @@ -21,6 +21,7 @@ package org.apache.qpid.ping; import java.util.List; +import java.util.Properties; import javax.jms.Destination; @@ -31,54 +32,36 @@ import org.apache.qpid.requestreply.PingPongProducer; * to send replies to its pings. It simply listens to its own ping destinations, rather than seperate reply queues. * It is an all in one ping client, that produces and consumes its own pings. * + *

    The constructor increments a count of the number of ping clients created. It is assumed that where many + * are created they will all be run in parallel and be active in sending and consuming pings at the same time. + * If the unique destinations flag is not set and a pub/sub ping cycle is being run, this means that they will all hear + * pings sent by each other. The expected number of pings received will therefore be multiplied up by the number of + * active ping clients. The {@link #getConsumersPerTopic()} method is used to supply this multiplier under these + * conditions. + * *

    *
    CRC Card
    Responsibilities Collaborations - *
    Create a ping pong producer that listens to its own pings {@link PingPongProducer} + *
    Create a ping producer that listens to its own pings {@link PingPongProducer} + *
    Count the number of ping producers and produce multiplier for scaling up messages expected over topic pings. *
    */ public class PingClient extends PingPongProducer { + /** Used to count the number of ping clients created. */ private static int _pingClientCount; /** - * Creates a ping producer with the specified parameters, of which there are many. See their individual comments - * for details. This constructor creates ping pong producer but de-registers its reply-to destination message - * listener, and replaces it by listening to all of its ping destinations. + * Creates a ping producer with the specified parameters, of which there are many. See the class level comments + * for {@link PingPongProducer} for details. This constructor creates a connection to the broker and creates + * producer and consumer sessions on it, to send and recieve its pings and replies on. * - * @param brokerDetails The URL of the broker to send pings to. - * @param username The username to log onto the broker with. - * @param password The password to log onto the broker with. - * @param virtualpath The virtual host name to use on the broker. - * @param destinationName The name (or root where multiple destinations are used) of the desitination to send - * pings to. - * @param selector The selector to filter replies with. - * @param transacted Indicates whether or not pings are sent and received in transactions. - * @param persistent Indicates whether pings are sent using peristent delivery. - * @param messageSize Specifies the size of ping messages to send. - * @param verbose Indicates that information should be printed to the console on every ping. - * @param afterCommit Indicates that the user should be promted to terminate a broker after commits to test failover. - * @param beforeCommit Indicates that the user should be promted to terminate a broker before commits to test failover. - * @param afterSend Indicates that the user should be promted to terminate a broker after sends to test failover. - * @param beforeSend Indicates that the user should be promted to terminate a broker before sends to test failover. - * @param failOnce Indicates that the failover testing behaviour should only happen on the first commit, not all. - * @param txBatchSize Specifies the number of pings to send in each transaction. - * @param noOfDestinations The number of destinations to ping. Must be 1 or more. - * @param rate Specified the number of pings per second to send. Setting this to 0 means send as fast as - * possible, with no rate restriction. - * @param pubsub True to ping topics, false to ping queues. - * @param unique True to use unique destinations for each ping pong producer, false to share. + * @param overrides Properties containing any desired overrides to the defaults. * * @throws Exception Any exceptions are allowed to fall through. */ - public PingClient(String brokerDetails, String username, String password, String virtualpath, String destinationName, - String selector, boolean transacted, boolean persistent, int messageSize, boolean verbose, - boolean afterCommit, boolean beforeCommit, boolean afterSend, boolean beforeSend, boolean failOnce, - int txBatchSize, int noOfDestinations, int rate, boolean pubsub, boolean unique, - int ackMode, long pausetime) throws Exception + public PingClient(Properties overrides) throws Exception { - super(brokerDetails, username, password, virtualpath, destinationName, selector, transacted, persistent, messageSize, - verbose, afterCommit, beforeCommit, afterSend, beforeSend, failOnce, txBatchSize, noOfDestinations, rate, - pubsub, unique, ackMode, pausetime); + super(overrides); _pingClientCount++; } @@ -94,6 +77,11 @@ public class PingClient extends PingPongProducer return _pingDestinations; } + /** + * Supplies the multiplier for the number of ping clients that will hear each ping when doing pub/sub pinging. + * + * @return The scaling up of the number of expected pub/sub pings. + */ public int getConsumersPerTopic() { if (_isUnique) diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java new file mode 100644 index 0000000000..77526141d6 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java @@ -0,0 +1,389 @@ +/* + * + * 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.qpid.ping; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Destination; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; + +import org.apache.log4j.Logger; + +import org.apache.qpid.requestreply.PingPongProducer; + +import uk.co.thebadgerset.junit.extensions.util.MathUtils; +import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; + +/** + * PingDurableClient is a variation of the {@link PingPongProducer} ping tool. Instead of sending its pings and + * receiving replies to them at the same time, this tool sends pings until it is signalled by some 'event' to stop + * sending. It then waits for another signal before it re-opens a fresh connection and attempts to receive all of the + * pings that it has succesfully sent. It is intended to be an interactive test that lets a user experiment with + * failure conditions when using durable messaging. + * + *

    The events that can stop it from sending are input from the user on the console, failure of its connection to + * the broker, completion of sending a specified number of messages, or expiry of a specified duration. In all cases + * it will do its best to clean up and close the connection before opening a fresh connection to receive the pings + * with. + * + *

    The event to re-connect and attempt to recieve the pings is input from the user on the console. + * + *

    This ping client inherits the configuration properties of its parent class ({@link PingPongProducer}) and + * additionally accepts the following parameters: + * + *

    + *
    Parameters
    Parameter Default Comments + *
    numMessages 100 The total number of messages to send. + *
    duration 30S The length of time to ping for. (Format dDhHmMsS, for d days, h hours, + * m minutes and s seconds). + *
    + * + *

    This ping client also overrides some of the defaults of its parent class, to provide a reasonable set up + * when no parameters are specified. + * + *

    + *
    Parameters
    Parameter Default Comments + *
    uniqueDests false Prevents destination names being timestamped. + *
    transacted true Only makes sense to test with transactions. + *
    persistent true Only makes sense to test persistent. + *
    commitBatchSize 10 + *
    rate 20 Total default test time is 5 seconds. + *
    + * + *

    When a number of messages or duration is specified, this ping client will ping until the first of those limits + * is reached. Reaching the limit will be interpreted as the first signal to stop sending, and the ping client will + * wait for the second signal before receiving its pings. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Send and receive pings. + *
    Accept user input to signal stop sending. + *
    Accept user input to signal start receiving. + *
    Provide feedback on pings sent versus pings received. + *
    + */ +public class PingDurableClient extends PingPongProducer implements ExceptionListener +{ + private static final Logger log = Logger.getLogger(PingDurableClient.class); + + public static final String NUM_MESSAGES_PROPNAME = "numMessages"; + public static final String NUM_MESSAGES_DEFAULT = "100"; + public static final String DURATION_PROPNAME = "duration"; + public static final String DURATION_DEFAULT = "30S"; + + /** The maximum length of time to wait whilst receiving pings before assuming that no more are coming. */ + private static final long TIME_OUT = 3000; + + static + { + defaults.setProperty(NUM_MESSAGES_PROPNAME, NUM_MESSAGES_DEFAULT); + defaults.setProperty(DURATION_PROPNAME, DURATION_DEFAULT); + defaults.setProperty(UNIQUE_DESTS_PROPNAME, "false"); + defaults.setProperty(TRANSACTED_PROPNAME, "true"); + defaults.setProperty(PERSISTENT_MODE_PROPNAME, "true"); + defaults.setProperty(TX_BATCH_SIZE_PROPNAME, "10"); + defaults.setProperty(RATE_PROPNAME, "20"); + } + + /** Specifies the number of pings to send, if larger than 0. 0 means send until told to stop. */ + private int numMessages; + + /** Sepcifies how long to ping for, if larger than 0. 0 means send until told to stop. */ + private long duration; + + /** Used to indciate that this application should terminate. Set by the shutdown hook. */ + private boolean terminate = false; + + /** + * @throws Exception Any exceptions are allowed to fall through. + */ + public PingDurableClient(Properties overrides) throws Exception + { + super(overrides); + log.debug("public PingDurableClient(Properties overrides = " + overrides + "): called"); + + // Extract the additional configuration parameters. + ParsedProperties properties = new ParsedProperties(defaults); + properties.putAll(overrides); + + numMessages = properties.getPropertyAsInteger(NUM_MESSAGES_PROPNAME); + String durationSpec = properties.getProperty(DURATION_PROPNAME); + + if (durationSpec != null) + { + duration = MathUtils.parseDuration(durationSpec) * 1000000; + } + } + + /** + * Starts the ping/wait/receive process. + * + * @param args The command line arguments. + */ + public static void main(String[] args) + { + try + { + // Create a ping producer overriding its defaults with all options passed on the command line. + Properties options = processCommandLine(args); + PingDurableClient pingProducer = new PingDurableClient(options); + + // Create a shutdown hook to terminate the ping-pong producer. + Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); + + // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. + // pingProducer.getConnection().setExceptionListener(pingProducer); + + // Run the test procedure. + int sent = pingProducer.send(); + pingProducer.waitForUser("Press return to begin receiving the pings."); + pingProducer.receive(sent); + + System.exit(0); + } + catch (Exception e) + { + System.err.println(e.getMessage()); + log.error("Top level handler caught execption.", e); + System.exit(1); + } + } + + /** + * Performs the main test procedure implemented by this ping client. See the class level comment for details. + */ + public int send() throws Exception + { + log.debug("public void sendWaitReceive(): called"); + + log.debug("duration = " + duration); + log.debug("numMessages = " + numMessages); + + if (duration > 0) + { + System.out.println("Sending for up to " + (duration / 1000000000f) + " seconds."); + } + + if (_rate > 0) + { + System.out.println("Sending at " + _rate + " messages per second."); + } + + if (numMessages > 0) + { + System.out.println("Sending up to " + numMessages + " messages."); + } + + // Establish the connection and the message producer. + establishConnection(true, false); + getConnection().start(); + + Message message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent); + + // Send pings until a terminating condition is received. + boolean endCondition = false; + int messagesSent = 0; + int messagesCommitted = 0; + int messagesNotCommitted = 0; + long start = System.nanoTime(); + + // Clear console in. + clearConsole(); + + while (!endCondition) + { + boolean committed = false; + + try + { + committed = sendMessage(messagesSent, message) && _transacted; + + messagesSent++; + messagesNotCommitted++; + + // Keep count of the number of messsages currently committed and pending commit. + if (committed) + { + log.debug("Adding " + messagesNotCommitted + " messages to the committed count."); + messagesCommitted += messagesNotCommitted; + messagesNotCommitted = 0; + + System.out.println("Commited: " + messagesCommitted); + } + } + catch (JMSException e) + { + log.debug("Got JMSException whilst sending."); + _publish = false; + } + + // Determine if the end condition has been met, based on the number of messages, time passed, errors on + // the connection or user input. + long now = System.nanoTime(); + + if ((duration != 0) && ((now - start) > duration)) + { + System.out.println("Send halted because duration expired."); + endCondition = true; + } + else if ((numMessages != 0) && (messagesSent >= numMessages)) + { + System.out.println("Send halted because # messages completed."); + endCondition = true; + } + else if (System.in.available() > 0) + { + System.out.println("Send halted by user input."); + endCondition = true; + + clearConsole(); + } + else if (!_publish) + { + System.out.println("Send halted by error on the connection."); + endCondition = true; + } + } + + log.debug("messagesSent = " + messagesSent); + log.debug("messagesCommitted = " + messagesCommitted); + log.debug("messagesNotCommitted = " + messagesNotCommitted); + + System.out.println("Messages sent: " + messagesSent + ", Messages Committed = " + messagesCommitted + + ", Messages not Committed = " + messagesNotCommitted); + + // Clean up the connection. + try + { + close(); + } + catch (JMSException e) + { + // Ignore as did best could manage to clean up. + } + + return messagesSent; + } + + private void receive(int messagesSent) throws Exception + { + // Re-establish the connection and the message consumer. + _queueJVMSequenceID = new AtomicInteger(); + _queueSharedID = new AtomicInteger(); + + establishConnection(false, true); + _consumer.setMessageListener(null); + _connection.start(); + + // Try to receive all of the pings that were successfully sent. + int messagesReceived = 0; + boolean endCondition = false; + + while (!endCondition) + { + // Message received = _consumer.receiveNoWait(); + Message received = _consumer.receive(TIME_OUT); + log.debug("received = " + received); + + if (received != null) + { + messagesReceived++; + } + + // Determine if the end condition has been met, based on the number of messages and time passed since last + // receiving a message. + if (received == null) + { + System.out.println("Timed out."); + endCondition = true; + } + else if (messagesReceived >= messagesSent) + { + System.out.println("Got all messages."); + endCondition = true; + } + } + + log.debug("messagesReceived = " + messagesReceived); + + System.out.println("Messages received: " + messagesReceived); + + // Clean up the connection. + close(); + } + + /** + * Clears any pending input from the console. + */ + private void clearConsole() + { + try + { + BufferedReader bis = new BufferedReader(new InputStreamReader(System.in)); + + // System.in.skip(System.in.available()); + while (bis.ready()) + { + bis.readLine(); + } + } + catch (IOException e) + { } + } + + /** + * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the + * effect of making this pinger listen to its own pings. + * + * @return The ping destinations. + */ + public List getReplyDestinations() + { + return _pingDestinations; + } + + /** + * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered with + * the runtime system as a shutdown hook. This shutdown hook sets an additional terminate flag, compared with the + * shutdown hook in {@link PingPongProducer}, because the publish flag is used to indicate that sending or receiving + * message should stop, not that the application should termiante. + * + * @return A shutdown hook for the ping loop. + */ + public Thread getShutdownHook() + { + return new Thread(new Runnable() + { + public void run() + { + stop(); + terminate = true; + } + }); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index c6a69807a3..44f7083bb5 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -34,20 +34,22 @@ import javax.jms.*; import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQNoConsumersException; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; -import org.apache.qpid.topic.Config; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.qpid.util.CommandLineParser; import uk.co.thebadgerset.junit.extensions.BatchedThrottle; import uk.co.thebadgerset.junit.extensions.Throttle; +import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; /** * PingPongProducer is a client that sends test messages, and waits for replies to these messages. The replies may @@ -65,31 +67,37 @@ import uk.co.thebadgerset.junit.extensions.Throttle; * transactions; control the number of pings to send in each transaction; limit its sending rate; and perform failover * testing. A complete list of accepted parameters, default values and comments on their usage is provided here: * - *

    - *
    CRC Card
    Parameter Default Comments - *
    messageSize 0 Message size in bytes. Not including any headers. - *
    destinationName ping The root name to use to generate destination names to ping. - *
    persistent false Determines whether peristent delivery is used. - *
    transacted false Determines whether messages are sent/received in transactions. + *

    + *
    Parameters
    Parameter Default Comments + *
    messageSize 0 Message size in bytes. Not including any headers. + *
    destinationName ping The root name to use to generate destination names to ping. + *
    persistent false Determines whether peristent delivery is used. + *
    transacted false Determines whether messages are sent/received in transactions. *
    broker tcp://localhost:5672 Determines the broker to connect to. - *
    virtualHost test Determines the virtual host to send all ping over. - *
    rate 0 The maximum rate (in hertz) to send messages at. 0 means no limit. - *
    verbose false The verbose flag for debugging. Prints to console on every message. - *
    pubsub false Whether to ping topics or queues. Uses p2p by default. - *
    failAfterCommit false Whether to prompt user to kill broker after a commit batch. - *
    failBeforeCommit false Whether to prompt user to kill broker before a commit batch. - *
    failAfterSend false Whether to prompt user to kill broker after a send. - *
    failBeforeSend false Whether to prompt user to kill broker before a send. - *
    failOnce true Whether to prompt for failover only once. - *
    username guest The username to access the broker with. - *
    password guest The password to access the broker with. - *
    selector null Not used. Defines a message selector to filter pings with. - *
    destinationCount 1 The number of receivers listening to the pings. - *
    timeout 30000 In milliseconds. The timeout to stop waiting for replies. - *
    commitBatchSize 1 The number of messages per transaction in transactional mode. - *
    uniqueDests true Whether each receiver only listens to one ping destination or all. - *
    ackMode NO_ACK The message acknowledgement mode. - *
    pauseBatch 0 In milliseconds. A pause to insert between transaction batches. + *
    virtualHost test Determines the virtual host to send all ping over. + *
    rate 0 The maximum rate (in hertz) to send messages at. 0 means no limit. + *
    verbose false The verbose flag for debugging. Prints to console on every message. + *
    pubsub false Whether to ping topics or queues. Uses p2p by default. + *
    failAfterCommit false Whether to prompt user to kill broker after a commit batch. + *
    failBeforeCommit false Whether to prompt user to kill broker before a commit batch. + *
    failAfterSend false Whether to prompt user to kill broker after a send. + *
    failBeforeSend false Whether to prompt user to kill broker before a send. + *
    failOnce true Whether to prompt for failover only once. + *
    username guest The username to access the broker with. + *
    password guest The password to access the broker with. + *
    selector null Not used. Defines a message selector to filter pings with. + *
    destinationCount 1 The number of receivers listening to the pings. + *
    timeout 30000 In milliseconds. The timeout to stop waiting for replies. + *
    commitBatchSize 1 The number of messages per transaction in transactional mode. + *
    uniqueDests true Whether each receiver only listens to one ping destination or all. + *
    ackMode AUTO_ACK The message acknowledgement mode. Possible values are: + * 0 - SESSION_TRANSACTED + * 1 - AUTO_ACKNOWLEDGE + * 2 - CLIENT_ACKNOWLEDGE + * 3 - DUPS_OK_ACKNOWLEDGE + * 257 - NO_ACKNOWLEDGE + * 258 - PRE_ACKNOWLEDGE + *
    pauseBatch 0 In milliseconds. A pause to insert between transaction batches. *
    * *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop @@ -121,7 +129,7 @@ import uk.co.thebadgerset.junit.extensions.Throttle; */ public class PingPongProducer implements Runnable, MessageListener, ExceptionListener { - private static final Logger _logger = Logger.getLogger(PingPongProducer.class); + private static final Logger log = Logger.getLogger(PingPongProducer.class); /** Holds the name of the property to get the test message size from. */ public static final String MESSAGE_SIZE_PROPNAME = "messageSize"; @@ -181,31 +189,31 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public static final String FAIL_AFTER_COMMIT_PROPNAME = "failAfterCommit"; /** Holds the default failover after commit test flag. */ - public static final String FAIL_AFTER_COMMIT_DEFAULT = "false"; + public static final boolean FAIL_AFTER_COMMIT_DEFAULT = false; /** Holds the name of the proeprty to get the fail before commit flag from. */ public static final String FAIL_BEFORE_COMMIT_PROPNAME = "failBeforeCommit"; /** Holds the default failover before commit test flag. */ - public static final String FAIL_BEFORE_COMMIT_DEFAULT = "false"; + public static final boolean FAIL_BEFORE_COMMIT_DEFAULT = false; /** Holds the name of the proeprty to get the fail after send flag from. */ public static final String FAIL_AFTER_SEND_PROPNAME = "failAfterSend"; /** Holds the default failover after send test flag. */ - public static final String FAIL_AFTER_SEND_DEFAULT = "false"; + public static final boolean FAIL_AFTER_SEND_DEFAULT = false; /** Holds the name of the property to get the fail before send flag from. */ public static final String FAIL_BEFORE_SEND_PROPNAME = "failBeforeSend"; /** Holds the default failover before send test flag. */ - public static final String FAIL_BEFORE_SEND_DEFAULT = "false"; + public static final boolean FAIL_BEFORE_SEND_DEFAULT = false; /** Holds the name of the property to get the fail once flag from. */ public static final String FAIL_ONCE_PROPNAME = "failOnce"; /** The default failover once flag, true means only do one failover, false means failover on every commit cycle. */ - public static final String FAIL_ONCE_DEFAULT = "true"; + public static final boolean FAIL_ONCE_DEFAULT = true; /** Holds the name of the property to get the broker access username from. */ public static final String USERNAME_PROPNAME = "username"; @@ -223,7 +231,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public static final String SELECTOR_PROPNAME = "selector"; /** Holds the default message selector. */ - public static final String SELECTOR_DEFAULT = null; + public static final String SELECTOR_DEFAULT = ""; /** Holds the name of the proeprty to get the destination count from. */ public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; @@ -253,7 +261,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public static final String ACK_MODE_PROPNAME = "ackMode"; /** Defines the default message acknowledgement mode. */ - public static final int ACK_MODE_DEFAULT = Session.NO_ACKNOWLEDGE; + public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; /** Holds the name of the property to get the pause between batches property from. */ public static final String PAUSE_AFTER_BATCH_PROPNAME = "pauseBatch"; @@ -273,96 +281,140 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Holds the name of the property to store nanosecond timestamps in ping messages with. */ public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp"; - /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ - private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); - - /** - * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross multiple - * ping producers on the same JVM. - */ - private static Map perCorrelationIds = - Collections.synchronizedMap(new HashMap()); + /** Holds the default configuration properties. */ + public static ParsedProperties defaults = new ParsedProperties(); - /** A convenient formatter to use when time stamping output. */ - protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); + static + { + defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT); + defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT); + defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT); + defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT); + defaults.setPropertyIfNull(PING_QUEUE_NAME_PROPNAME, PING_QUEUE_NAME_DEFAULT); + defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT); + defaults.setPropertyIfNull(TRANSACTED_PROPNAME, TRANSACTED_DEFAULT); + defaults.setPropertyIfNull(PERSISTENT_MODE_PROPNAME, PERSISTENT_MODE_DEFAULT); + defaults.setPropertyIfNull(ACK_MODE_PROPNAME, ACK_MODE_DEFAULT); + defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT); + defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT); + defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT); + defaults.setPropertyIfNull(UNIQUE_DESTS_PROPNAME, UNIQUE_DESTS_DEFAULT); + defaults.setPropertyIfNull(FAIL_BEFORE_COMMIT_PROPNAME, FAIL_BEFORE_COMMIT_DEFAULT); + defaults.setPropertyIfNull(FAIL_AFTER_COMMIT_PROPNAME, FAIL_AFTER_COMMIT_DEFAULT); + defaults.setPropertyIfNull(FAIL_BEFORE_SEND_PROPNAME, FAIL_BEFORE_SEND_DEFAULT); + defaults.setPropertyIfNull(FAIL_AFTER_SEND_PROPNAME, FAIL_AFTER_SEND_DEFAULT); + defaults.setPropertyIfNull(FAIL_ONCE_PROPNAME, FAIL_ONCE_DEFAULT); + defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT); + defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT); + defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT); + defaults.setPropertyIfNull(PAUSE_AFTER_BATCH_PROPNAME, PAUSE_AFTER_BATCH_DEFAULT); + defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT); + } - /** - * This id generator is used to generate ids to append to the queue name to ensure that queues can be unique when - * creating multiple ping producers in the same JVM. - */ - protected static AtomicInteger _queueJVMSequenceID = new AtomicInteger(); - - /** Holds the destination where the response messages will arrive. */ - private Destination _replyDestination; + protected String _brokerDetails; + protected String _username; + protected String _password; + protected String _virtualpath; + protected String _destinationName; + protected String _selector; + protected boolean _transacted; /** Determines whether this producer sends persistent messages. */ protected boolean _persistent; /** Holds the acknowledgement mode used for sending and receiving messages. */ - private int _ackMode = Session.NO_ACKNOWLEDGE; + private int _ackMode; /** Determines what size of messages this producer sends. */ protected int _messageSize; /** Used to indicate that the ping loop should print out whenever it pings. */ - protected boolean _verbose = VERBOSE_DEFAULT; + protected boolean _verbose; - /** Holds the session on which ping replies are received. */ - protected Session _consumerSession; + /** Flag used to indicate if this is a point to point or pub/sub ping client. */ + protected boolean _isPubSub; - /** Used to restrict the sending rate to a specified limit. */ - private Throttle _rateLimiter = null; + /** Flag used to indicate if the destinations should be unique client. */ + protected boolean _isUnique; - /** Holds a message listener that this message listener chains all its messages to. */ - private ChainedMessageListener _chainedMessageListener = null; + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ + protected boolean _failBeforeCommit; - /** Flag used to indicate if this is a point to point or pub/sub ping client. */ - protected boolean _isPubSub = PUBSUB_DEFAULT; + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ + protected boolean _failAfterCommit; - /** Flag used to indicate if the destinations should be unique client. */ - protected static boolean _isUnique = UNIQUE_DESTS_DEFAULT; + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ + protected boolean _failBeforeSend; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ + protected boolean _failAfterSend; + + /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ + protected boolean _failOnce; + + /** Holds the number of sends that should be performed in every transaction when using transactions. */ + protected int _txBatchSize; + + protected int _noOfDestinations; + protected int _rate; + + /** Holds the wait time to insert between every batch of messages committed. */ + private long _pauseBatch; + + /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ + private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); /** - * This id generator is used to generates ids that are only unique within this pinger. Creating multiple pingers - * on the same JVM using this id generator will allow them to ping on the same queues. + * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross multiple + * ping producers on the same JVM. */ - protected AtomicInteger _queueSharedId = new AtomicInteger(); + private static Map perCorrelationIds = + Collections.synchronizedMap(new HashMap()); - /** Used to tell the ping loop when to terminate, it only runs while this is true. */ - protected boolean _publish = true; + /** A convenient formatter to use when time stamping output. */ + protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); /** Holds the connection to the broker. */ - private Connection _connection; + protected Connection _connection; + + /** Holds the session on which ping replies are received. */ + protected Session _consumerSession; /** Holds the producer session, needed to create ping messages. */ - private Session _producerSession; + protected Session _producerSession; - /** Holds the set of destinations that this ping producer pings. */ - protected List _pingDestinations = new ArrayList(); + /** Holds the destination where the response messages will arrive. */ + protected Destination _replyDestination; - /** Holds the message producer to send the pings through. */ - protected MessageProducer _producer; + /** Holds the set of destinations that this ping producer pings. */ + protected List _pingDestinations; - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ - protected boolean _failBeforeCommit = false; + /** Used to restrict the sending rate to a specified limit. */ + protected Throttle _rateLimiter; - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ - protected boolean _failAfterCommit = false; + /** Holds a message listener that this message listener chains all its messages to. */ + protected ChainedMessageListener _chainedMessageListener = null; - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ - protected boolean _failBeforeSend = false; + /** + * This id generator is used to generate ids to append to the queue name to ensure that queues can be unique when + * creating multiple ping producers in the same JVM. + */ + protected static AtomicInteger _queueJVMSequenceID = new AtomicInteger(); - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ - protected boolean _failAfterSend = false; + /** + * This id generator is used to generates ids that are only unique within this pinger. Creating multiple pingers + * on the same JVM using this id generator will allow them to ping on the same queues. + */ + protected AtomicInteger _queueSharedID = new AtomicInteger(); - /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ - protected boolean _failOnce = true; + /** Used to tell the ping loop when to terminate, it only runs while this is true. */ + protected boolean _publish = true; - /** Holds the number of sends that should be performed in every transaction when using transactions. */ - protected int _txBatchSize = TX_BATCH_SIZE_DEFAULT; + /** Holds the message producer to send the pings through. */ + protected MessageProducer _producer; - /** Holds the wait time to insert between every batch of messages committed. */ - private static long _pauseBatch = PAUSE_AFTER_BATCH_DEFAULT; + /** Holds the message consumer to receive the ping replies through. */ + protected MessageConsumer _consumer; /** * Holds the number of consumers that will be attached to each topic. Each pings will result in a reply from each of the @@ -370,202 +422,195 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ static int _consumersPerTopic = 1; + /** The prompt to display when asking the user to kill the broker for failover testing. */ + private static final String KILL_BROKER_PROMPT = "Kill broker now, then press Return."; + /** - * Creates a ping producer with the specified parameters, of which there are many. See their individual comments for - * details. This constructor creates a connection to the broker and creates producer and consumer sessions on it, to send - * and recieve its pings and replies on. The other options are kept, and control how this pinger behaves. + * Creates a ping producer with the specified parameters, of which there are many. See the class level comments + * for details. This constructor creates a connection to the broker and creates producer and consumer sessions on + * it, to send and recieve its pings and replies on. * - * @param brokerDetails The URL of the broker to send pings to. - * @param username The username to log onto the broker with. - * @param password The password to log onto the broker with. - * @param virtualpath The virtual host name to use on the broker. - * @param destinationName The name (or root where multiple destinations are used) of the desitination to send pings to. - * @param selector The selector to filter replies with. - * @param transacted Indicates whether or not pings are sent and received in transactions. - * @param persistent Indicates whether pings are sent using peristent delivery. - * @param messageSize Specifies the size of ping messages to send. - * @param verbose Indicates that information should be printed to the console on every ping. - * @param afterCommit Indicates that the user should be promted to terminate a broker after commits to test - * failover. - * @param beforeCommit Indicates that the user should be promted to terminate a broker before commits to test - * failover. - * @param afterSend Indicates that the user should be promted to terminate a broker after sends to test failover. - * @param beforeSend Indicates that the user should be promted to terminate a broker before sends to test - * failover. - * @param failOnce Indicates that the failover testing behaviour should only happen on the first commit, not - * all. - * @param txBatchSize Specifies the number of pings to send in each transaction. - * @param noOfDestinations The number of destinations to ping. Must be 1 or more. - * @param rate Specified the number of pings per second to send. Setting this to 0 means send as fast as - * possible, with no rate restriction. - * @param pubsub True to ping topics, false to ping queues. - * @param unique True to use unique destinations for each ping pong producer, false to share. + * @param overrides Properties containing any desired overrides to the defaults. * * @throws Exception Any exceptions are allowed to fall through. */ - public PingPongProducer(String brokerDetails, String username, String password, String virtualpath, - String destinationName, String selector, boolean transacted, boolean persistent, int messageSize, - boolean verbose, boolean afterCommit, boolean beforeCommit, boolean afterSend, - boolean beforeSend, boolean failOnce, int txBatchSize, int noOfDestinations, int rate, - boolean pubsub, boolean unique, int ackMode, long pause) throws Exception + public PingPongProducer(Properties overrides) throws Exception { - _logger.debug("public PingPongProducer(String brokerDetails = " + brokerDetails + ", String username = " + username - + ", String password = " + password + ", String virtualpath = " + virtualpath - + ", String destinationName = " + destinationName + ", String selector = " + selector - + ", boolean transacted = " + transacted + ", boolean persistent = " + persistent - + ", int messageSize = " + messageSize + ", boolean verbose = " + verbose + ", boolean afterCommit = " - + afterCommit + ", boolean beforeCommit = " + beforeCommit + ", boolean afterSend = " + afterSend - + ", boolean beforeSend = " + beforeSend + ", boolean failOnce = " + failOnce + ", int txBatchSize = " - + txBatchSize + ", int noOfDestinations = " + noOfDestinations + ", int rate = " + rate - + ", boolean pubsub = " + pubsub + ", boolean unique = " + unique + ", ackMode = " + ackMode - + "): called"); - - // Keep all the relevant options. - _persistent = persistent; - _messageSize = messageSize; - _verbose = verbose; - _failAfterCommit = afterCommit; - _failBeforeCommit = beforeCommit; - _failAfterSend = afterSend; - _failBeforeSend = beforeSend; - _failOnce = failOnce; - _txBatchSize = txBatchSize; - _isPubSub = pubsub; - _isUnique = unique; - _pauseBatch = pause; - - if (ackMode != 0) - { - _ackMode = ackMode; - } + log.debug("public PingPongProducer(Properties overrides = " + overrides + "): called"); + + // Create a set of parsed properties from the defaults overriden by the passed in values. + ParsedProperties properties = new ParsedProperties(defaults); + properties.putAll(overrides); + + // Extract the configuration properties to set the pinger up with. + _brokerDetails = properties.getProperty(BROKER_PROPNAME); + _username = properties.getProperty(USERNAME_PROPNAME); + _password = properties.getProperty(PASSWORD_PROPNAME); + _virtualpath = properties.getProperty(VIRTUAL_HOST_PROPNAME); + _destinationName = properties.getProperty(PING_QUEUE_NAME_PROPNAME); + _selector = properties.getProperty(SELECTOR_PROPNAME); + _transacted = properties.getPropertyAsBoolean(TRANSACTED_PROPNAME); + _persistent = properties.getPropertyAsBoolean(PERSISTENT_MODE_PROPNAME); + _messageSize = properties.getPropertyAsInteger(MESSAGE_SIZE_PROPNAME); + _verbose = properties.getPropertyAsBoolean(VERBOSE_PROPNAME); + _failAfterCommit = properties.getPropertyAsBoolean(FAIL_AFTER_COMMIT_PROPNAME); + _failBeforeCommit = properties.getPropertyAsBoolean(FAIL_BEFORE_COMMIT_PROPNAME); + _failAfterSend = properties.getPropertyAsBoolean(FAIL_AFTER_SEND_PROPNAME); + _failBeforeSend = properties.getPropertyAsBoolean(FAIL_BEFORE_SEND_PROPNAME); + _failOnce = properties.getPropertyAsBoolean(FAIL_ONCE_PROPNAME); + _txBatchSize = properties.getPropertyAsInteger(TX_BATCH_SIZE_PROPNAME); + _noOfDestinations = properties.getPropertyAsInteger(DESTINATION_COUNT_PROPNAME); + _rate = properties.getPropertyAsInteger(RATE_PROPNAME); + _isPubSub = properties.getPropertyAsBoolean(PUBSUB_PROPNAME); + _isUnique = properties.getPropertyAsBoolean(UNIQUE_DESTS_PROPNAME); + _ackMode = properties.getPropertyAsInteger(ACK_MODE_PROPNAME); + _pauseBatch = properties.getPropertyAsLong(PAUSE_AFTER_BATCH_PROPNAME); // Check that one or more destinations were specified. - if (noOfDestinations < 1) + if (_noOfDestinations < 1) { throw new IllegalArgumentException("There must be at least one destination."); } - // Create a connection to the broker. + // Set up a throttle to control the send rate, if a rate > 0 is specified. + if (_rate > 0) + { + _rateLimiter = new BatchedThrottle(); + _rateLimiter.setRate(_rate); + } + + // Create the connection and message producers/consumers. + // establishConnection(true, true); + } + + /** + * Establishes a connection to the broker and creates message consumers and producers based on the parameters + * that this ping client was created with. + * + * @param producer Flag to indicate whether or not the producer should be set up. + * @param consumer Flag to indicate whether or not the consumers should be set up. + * + * @throws Exception Any exceptions are allowed to fall through. + */ + public void establishConnection(boolean producer, boolean consumer) throws Exception + { + log.debug("public void establishConnection(): called"); + + // Generate a unique identifying name for this client, based on it ip address and the current time. InetAddress address = InetAddress.getLocalHost(); String clientID = address.getHostName() + System.currentTimeMillis(); - _connection = new AMQConnection(brokerDetails, username, password, clientID, virtualpath); + // Create a connection to the broker. + createConnection(clientID); // Create transactional or non-transactional sessions, based on the command line arguments. - _producerSession = (Session) getConnection().createSession(transacted, _ackMode); - _consumerSession = (Session) getConnection().createSession(transacted, _ackMode); + _producerSession = (Session) getConnection().createSession(_transacted, _ackMode); + _consumerSession = (Session) getConnection().createSession(_transacted, _ackMode); - // Set up a throttle to control the send rate, if a rate > 0 is specified. - if (rate > 0) + // Create the destinations to send pings to and receive replies from. + _replyDestination = _consumerSession.createTemporaryQueue(); + createPingDestinations(_noOfDestinations, _selector, _destinationName, _isUnique); + + // Create the message producer only if instructed to. + if (producer) { - _rateLimiter = new BatchedThrottle(); - _rateLimiter.setRate(rate); + createProducer(); } - // Create the temporary queue for replies. - _replyDestination = _consumerSession.createTemporaryQueue(); + // Create the message consumer only if instructed to. + if (consumer) + { + createReplyConsumers(getReplyDestinations(), _selector); + } + } - // Create the producer and the consumers for all reply destinations. - createProducer(); - createPingDestinations(noOfDestinations, selector, destinationName, unique); - createReplyConsumers(getReplyDestinations(), selector); + /** + * Establishes a connection to the broker, based on the configuration parameters that this ping client was + * created with. + * + * @param clientID The clients identifier. + * + * @throws AMQException Any underlying exceptions are allowed to fall through. + * @throws URLSyntaxException Any underlying exceptions are allowed to fall through. + */ + protected void createConnection(String clientID) throws AMQException, URLSyntaxException + { + _connection = new AMQConnection(_brokerDetails, _username, _password, clientID, _virtualpath); } /** - * Starts a ping-pong loop running from the command line. The bounce back client {@link PingPongBouncer} also needs to be - * started to bounce the pings back again. + * Starts a ping-pong loop running from the command line. The bounce back client {@link PingPongBouncer} also needs + * to be started to bounce the pings back again. * * @param args The command line arguments. - * - * @throws Exception When something went wrong with the test */ - public static void main(String[] args) throws Exception + public static void main(String[] args) { - // Extract the command line. - Config config = new Config(); - config.setOptions(args); - if (args.length == 0) + try { - _logger.info("Running test with default values..."); - // usage(); - // System.exit(0); - } + Properties options = processCommandLine(args); - String brokerDetails = config.getHost() + ":" + config.getPort(); - String virtualpath = VIRTUAL_HOST_DEFAULT; - String selector = (config.getSelector() == null) ? SELECTOR_DEFAULT : config.getSelector(); - boolean verbose = true; - boolean transacted = config.isTransacted(); - boolean persistent = config.usePersistentMessages(); - int messageSize = (config.getPayload() != 0) ? config.getPayload() : MESSAGE_SIZE_DEAFULT; - // int messageCount = config.getMessages(); - int destCount = (config.getDestinationsCount() != 0) ? config.getDestinationsCount() : DESTINATION_COUNT_DEFAULT; - int batchSize = (config.getBatchSize() != 0) ? config.getBatchSize() : TX_BATCH_SIZE_DEFAULT; - int rate = (config.getRate() != 0) ? config.getRate() : RATE_DEFAULT; - boolean pubsub = config.isPubSub(); - - String destName = config.getDestination(); - if (destName == null) - { - destName = PING_QUEUE_NAME_DEFAULT; - } + // Create a ping producer overriding its defaults with all options passed on the command line. + PingPongProducer pingProducer = new PingPongProducer(options); + pingProducer.establishConnection(true, true); - boolean afterCommit = false; - boolean beforeCommit = false; - boolean afterSend = false; - boolean beforeSend = false; - boolean failOnce = false; + // Start the ping producers dispatch thread running. + pingProducer.getConnection().start(); - for (String arg : args) - { - if (arg.startsWith("failover:")) - { - // failover:: | failover:once - String[] parts = arg.split(":"); - if (parts.length == 3) - { - if (parts[2].equals("commit")) - { - afterCommit = parts[1].equals("after"); - beforeCommit = parts[1].equals("before"); - } + // Create a shutdown hook to terminate the ping-pong producer. + Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); - if (parts[2].equals("send")) - { - afterSend = parts[1].equals("after"); - beforeSend = parts[1].equals("before"); - } + // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. + pingProducer.getConnection().setExceptionListener(pingProducer); - if (parts[1].equals("once")) - { - failOnce = true; - } - } - else - { - System.out.println("Unrecognized failover request:" + arg); - } - } + // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. + Thread pingThread = new Thread(pingProducer); + pingThread.run(); + pingThread.join(); } + catch (Exception e) + { + System.err.println(e.getMessage()); + log.error("Top level handler caught execption.", e); + System.exit(1); + } + } - // Create a ping producer to handle the request/wait/reply cycle. - PingPongProducer pingProducer = - new PingPongProducer(brokerDetails, USERNAME_DEFAULT, PASSWORD_DEFAULT, virtualpath, destName, selector, - transacted, persistent, messageSize, verbose, afterCommit, beforeCommit, afterSend, - beforeSend, failOnce, batchSize, destCount, rate, pubsub, false, 0, 0); + /** + * Extracts all name=value pairs from the command line, sets them all as system properties and also returns + * a map of properties containing them. + * + * @param args The command line. + * + * @return A set of properties containing all name=value pairs from the command line. + * + * @todo This is a commonly used piece of code. Make it accept a command line definition and move it into the + * CommandLineParser class. + */ + protected static Properties processCommandLine(String[] args) + { + // Use the command line parser to evaluate the command line. + CommandLineParser commandLine = new CommandLineParser(new String[][] {}); - pingProducer.getConnection().start(); + // Capture the command line arguments or display errors and correct usage and then exit. + Properties options = null; - // Create a shutdown hook to terminate the ping-pong producer. - Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); + try + { + options = commandLine.parseCommandLine(args); - // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. - pingProducer.getConnection().setExceptionListener(pingProducer); + // Add all the trailing command line options (name=value pairs) to system properties. Tests may pick up + // overridden values from there. + commandLine.addCommandLineToSysProperties(); + } + catch (IllegalArgumentException e) + { + System.out.println(commandLine.getErrors()); + System.out.println(commandLine.getUsage()); + System.exit(1); + } - // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. - Thread pingThread = new Thread(pingProducer); - pingThread.run(); - pingThread.join(); + return options; } /** @@ -582,9 +627,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis Thread.sleep(sleepTime); } catch (InterruptedException ie) - { - // ignore - } + { } } } @@ -596,27 +639,30 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public List getReplyDestinations() { - _logger.debug("public List getReplyDestinations(): called"); + log.debug("public List getReplyDestinations(): called"); List replyDestinations = new ArrayList(); replyDestinations.add(_replyDestination); + log.debug("replyDestinations = " + replyDestinations); + return replyDestinations; } /** - * Creates the producer to send the pings on. This is created without a default destination. Its persistent delivery flag - * is set accoring the ping producer creation options. + * Creates the producer to send the pings on. This is created without a default destination. Its persistent delivery + * flag is set accoring the ping producer creation options. * * @throws JMSException Any JMSExceptions are allowed to fall through. */ public void createProducer() throws JMSException { - _logger.debug("public void createProducer(): called"); + log.debug("public void createProducer(): called"); _producer = (MessageProducer) _producerSession.createProducer(null); - // _producer.setDisableMessageTimestamp(true); _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + log.debug("Created producer for " + (_persistent ? "persistent" : "non-persistent") + " messages."); } /** @@ -632,13 +678,16 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * @throws JMSException Any JMSExceptions are allowed to fall through. */ public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique) - throws JMSException + throws JMSException { - _logger.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations - + ", String selector = " + selector + ", String rootName = " + rootName + ", boolean unique = " - + unique + "): called"); + log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " + + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + "): called"); + + _pingDestinations = new ArrayList(); // Create the desired number of ping destinations and consumers for them. + log.debug("Creating " + noOfDestinations + " destinations to ping."); + for (int i = 0; i < noOfDestinations; i++) { AMQDestination destination; @@ -648,26 +697,26 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag. if (unique) { - _logger.debug("Creating unique destinations."); + log.debug("Creating unique destinations."); id = "_" + _queueJVMSequenceID.incrementAndGet() + "_" + _connection.getClientID(); } else { - _logger.debug("Creating shared destinations."); - id = "_" + _queueSharedId.incrementAndGet(); + log.debug("Creating shared destinations."); + id = "_" + _queueSharedID.incrementAndGet(); } // Check if this is a pub/sub pinger, in which case create topics. if (_isPubSub) { destination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id); - _logger.debug("Created topic " + destination); + log.debug("Created topic " + destination); } // Otherwise this is a p2p pinger, in which case create queues. else { destination = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, rootName + id); - _logger.debug("Created queue " + destination); + log.debug("Created queue " + destination); } // Keep the destination. @@ -675,6 +724,29 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } } + /** + * Creates consumers for the specified destinations and registers this pinger to listen to their messages. + * + * @param destinations The destinations to listen to. + * @param selector A selector to filter the messages with. + * + * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through. + */ + public void createReplyConsumers(Collection destinations, String selector) throws JMSException + { + log.debug("public void createReplyConsumers(Collection destinations = " + destinations + + ", String selector = " + selector + "): called"); + + for (Destination destination : destinations) + { + // Create a consumer for the destination and set this pinger to listen to its messages. + _consumer = + _consumerSession.createConsumer(destination, PREFETCH_DEFAULT, NO_LOCAL_DEFAULT, EXCLUSIVE_DEFAULT, + selector); + _consumer.setMessageListener(this); + } + } + /** * Stores the received message in the replies map, then resets the boolean latch that a thread waiting for a correlating * reply may be waiting on. This is only done if the reply has a correlation id that is expected in the replies map. @@ -683,13 +755,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public void onMessage(Message message) { - _logger.debug("public void onMessage(Message message): called"); + log.debug("public void onMessage(Message message): called"); try { // Extract the messages correlation id. String correlationID = message.getJMSCorrelationID(); - _logger.debug("correlationID = " + correlationID); + log.debug("correlationID = " + correlationID); // Countdown on the traffic light if there is one for the matching correlation id. PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); @@ -701,7 +773,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Restart the timeout timer on every message. perCorrelationId.timeOutStart = System.nanoTime(); - _logger.debug("Reply was expected, decrementing the latch for the id, " + correlationID); + log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); // Decrement the countdown latch. Before this point, it is possible that two threads might enter this // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block @@ -716,20 +788,14 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis trueCount = trafficLight.getCount(); remainingCount = trueCount - 1; - _logger.debug("remainingCount = " + remainingCount); - _logger.debug("trueCount = " + trueCount); + log.debug("remainingCount = " + remainingCount); + log.debug("trueCount = " + trueCount); // Commit on transaction batch size boundaries. At this point in time the waiting producer remains // blocked, even on the last message. if ((remainingCount % _txBatchSize) == 0) { commitTx(_consumerSession); - if (!_consumerSession.getTransacted() && - _consumerSession.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) - { - // Acknowledge the messages when the session is not transacted but client_ack - ((AMQSession) _consumerSession).acknowledge(); - } } // Forward the message and remaining count to any interested chained message listener. @@ -748,7 +814,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } else { - _logger.warn("Got unexpected message with correlationId: " + correlationID); + log.warn("Got unexpected message with correlationId: " + correlationID); } // Print out ping times for every message in verbose mode only. @@ -759,48 +825,16 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis if (timestamp != null) { long diff = System.nanoTime() - timestamp; - _logger.trace("Time for round trip (nanos): " + diff); + log.trace("Time for round trip (nanos): " + diff); } } } catch (JMSException e) { - _logger.warn("There was a JMSException: " + e.getMessage(), e); + log.warn("There was a JMSException: " + e.getMessage(), e); } - _logger.debug("public void onMessage(Message message): ending"); - } - - /** - * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out before a - * reply arrives, then a null reply is returned from this method. This method generates a new unqiue correlation id for - * the messages. - * - * @param message The message to send. - * @param numPings The number of ping messages to send. - * @param timeout The timeout in milliseconds. - * - * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait for - * all prematurely. - * - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - * @throws InterruptedException When interrupted by a timeout. - */ - public int pingAndWaitForReply(Message message, int numPings, long timeout) throws JMSException, InterruptedException - { - _logger.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " - + timeout + "): called"); - - // Create a unique correlation id to put on the messages before sending them. - String messageCorrelationId = Long.toString(_correlationIdGenerator.incrementAndGet()); - - return pingAndWaitForReply(message, numPings, timeout, messageCorrelationId); - } - - public int pingAndWaitForReply(int numPings, long timeout, String messageCorrelationId) - throws JMSException, InterruptedException - { - return pingAndWaitForReply(null, numPings, timeout, messageCorrelationId); + log.debug("public void onMessage(Message message): ending"); } /** @@ -808,10 +842,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * reply arrives, then a null reply is returned from this method. This method allows the caller to specify the * correlation id. * - * @param message The message to send. + * @param message The message to send. If this is null, one is generated. * @param numPings The number of ping messages to send. * @param timeout The timeout in milliseconds. - * @param messageCorrelationId The message correlation id. + * @param messageCorrelationId The message correlation id. If this is null, one is generated. * * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait for * all prematurely. @@ -820,10 +854,16 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * @throws InterruptedException When interrupted by a timeout */ public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) - throws JMSException, InterruptedException + throws JMSException, InterruptedException { - _logger.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " - + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called"); + log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called"); + + // Generate a unique correlation id to put on the messages before sending them, if one was not specified. + if (messageCorrelationId == null) + { + messageCorrelationId = Long.toString(_correlationIdGenerator.incrementAndGet()); + } try { @@ -858,31 +898,31 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis allMessagesReceived = numReplies == getExpectedNumPings(numPings); - _logger.debug("numReplies = " + numReplies); - _logger.debug("allMessagesReceived = " + allMessagesReceived); + log.debug("numReplies = " + numReplies); + log.debug("allMessagesReceived = " + allMessagesReceived); // Recheck the timeout condition. long now = System.nanoTime(); long lastMessageReceievedAt = perCorrelationId.timeOutStart; timedOut = (now - lastMessageReceievedAt) > (timeout * 1000000); - _logger.debug("now = " + now); - _logger.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); + log.debug("now = " + now); + log.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); } while (!timedOut && !allMessagesReceived); if ((numReplies < getExpectedNumPings(numPings)) && _verbose) { - _logger.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); + log.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); } else if (_verbose) { - _logger.info("Got all replies on id, " + messageCorrelationId); + log.info("Got all replies on id, " + messageCorrelationId); } commitTx(_consumerSession); - _logger.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); + log.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); return numReplies; } @@ -905,8 +945,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException { - _logger.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings - + ", String messageCorrelationId = " + messageCorrelationId + "): called"); + log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings + + ", String messageCorrelationId = " + messageCorrelationId + "): called"); if (message == null) { @@ -923,40 +963,19 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Send all of the ping messages. for (int i = 0; i < numPings; i++) { - // Reset the committed flag to indicate that there are uncommitted messages. + // Reset the committed flag to indicate that there may be uncommitted messages. committed = false; // Re-timestamp the message. message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); - // Round robin the destinations as the messages are sent. - // return _destinationCount; - sendMessage(_pingDestinations.get(i % _pingDestinations.size()), message); - - // Apply message rate throttling if a rate limit has been set up. - if (_rateLimiter != null) - { - _rateLimiter.throttle(); - } - - // Call commit every time the commit batch size is reached. - if ((i % _txBatchSize) == 0) - { - commitTx(_producerSession); - committed = true; - - /* This pause is required for some cases. eg in load testing when sessions are non-transacted the - Mina IO layer can't clear the cache in time. So this pause gives enough time for mina to clear - the cache (without this mina throws OutOfMemoryError). pause() will check if time is != 0 - */ - pause(_pauseBatch); - } + // Send the message, passing in the message count. + committed = sendMessage(i, message); // Spew out per message timings on every message sonly in verbose mode. if (_verbose) { - _logger.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " - + messageCorrelationId); + log.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); } } @@ -968,7 +987,70 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * The ping loop implementation. This sends out pings waits for replies and inserts short pauses in between each. + * Sends the sepcified message, applies rate limiting and possibly commits the current transaction. The count of + * messages sent so far must be specified and is used to round robin the ping destinations (where there are more + * than one), and to determine if the transaction batch size has been reached and the sent messages should be + * committed. + * + * @param i The count of messages sent so far in a loop of multiple calls to this send method. + * @param message The message to send. + * + * @return true if the messages were committed, false otherwise. + * + * @throws JMSException All underlyiung JMSExceptions are allowed to fall through. + */ + protected boolean sendMessage(int i, Message message) throws JMSException + { + // log.debug("protected boolean sendMessage(int i = " + i + ", Message message): called"); + // log.debug("_txBatchSize = " + _txBatchSize); + + // Round robin the destinations as the messages are sent. + Destination destination = _pingDestinations.get(i % _pingDestinations.size()); + + // Prompt the user to kill the broker when doing failover testing. + if (_failBeforeSend) + { + if (_failOnce) + { + _failBeforeSend = false; + } + + log.trace("Failing Before Send"); + waitForUser(KILL_BROKER_PROMPT); + } + + // Send the message either to its round robin destination, or its default destination. + if (destination == null) + { + _producer.send(message); + } + else + { + _producer.send(destination, message); + } + + // Apply message rate throttling if a rate limit has been set up. + if (_rateLimiter != null) + { + _rateLimiter.throttle(); + } + + // Call commit every time the commit batch size is reached. + boolean committed = false; + + // Commit on every transaction batch size boundary. Here i + 1 is the count of actual messages sent. + if (((i + 1) % _txBatchSize) == 0) + { + committed = commitTx(_producerSession); + } + + return committed; + } + + /** + * Implements a single iteration of the ping loop. This sends the number of pings specified by the transaction + * batch size property, and waits for replies to all of them. Any errors cause the publish flag to be cleared, + * which will terminate the pinger. */ public void pingLoop() { @@ -979,25 +1061,20 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); // Send the message and wait for a reply. - pingAndWaitForReply(msg, TX_BATCH_SIZE_DEFAULT, TIMEOUT_DEFAULT); + pingAndWaitForReply(msg, TX_BATCH_SIZE_DEFAULT, TIMEOUT_DEFAULT, null); } catch (JMSException e) { _publish = false; - _logger.debug("There was a JMSException: " + e.getMessage(), e); + log.debug("There was a JMSException: " + e.getMessage(), e); } catch (InterruptedException e) { _publish = false; - _logger.debug("There was an interruption: " + e.getMessage(), e); + log.debug("There was an interruption: " + e.getMessage(), e); } } - public Destination getReplyDestination() - { - return getReplyDestinations().get(0); - } - /** * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set here. * @@ -1038,8 +1115,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this flag has - * been cleared. + * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this + * flag has been cleared. */ public void stop() { @@ -1066,8 +1143,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public void onException(JMSException e) { + log.debug("public void onException(JMSException e = " + e + "): called", e); _publish = false; - _logger.debug("There was a JMSException: " + e.getMessage(), e); } /** @@ -1079,12 +1156,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public Thread getShutdownHook() { return new Thread(new Runnable() - { - public void run() { - stop(); - } - }); + public void run() + { + stop(); + } + }); } /** @@ -1097,29 +1174,6 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis return _connection; } - /** - * Creates consumers for the specified destinations and registers this pinger to listen to their messages. - * - * @param destinations The destinations to listen to. - * @param selector A selector to filter the messages with. - * - * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through. - */ - public void createReplyConsumers(Collection destinations, String selector) throws JMSException - { - _logger.debug("public void createReplyConsumers(Collection destinations = " + destinations - + ", String selector = " + selector + "): called"); - - for (Destination destination : destinations) - { - // Create a consumer for the destination and set this pinger to listen to its messages. - MessageConsumer consumer = - _consumerSession.createConsumer(destination, PREFETCH_DEFAULT, NO_LOCAL_DEFAULT, EXCLUSIVE_DEFAULT, - selector); - consumer.setMessageListener(this); - } - } - /** * Closes the pingers connection. * @@ -1127,11 +1181,24 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public void close() throws JMSException { - _logger.debug("public void close(): called"); + log.debug("public void close(): called"); - if (_connection != null) + try + { + if (_connection != null) + { + _connection.close(); + } + } + finally { - _connection.close(); + _connection = null; + _producerSession = null; + _consumerSession = null; + _producer = null; + _consumer = null; + _pingDestinations = null; + _replyDestination = null; } } @@ -1150,25 +1217,29 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * * @throws javax.jms.JMSException If the commit fails and then the rollback fails. * + * @return true if the session was committed, false if it was not. + * * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit * method, because commits only apply to transactional pingers, but fail after send applied to transactional and * non-transactional alike. */ - protected void commitTx(Session session) throws JMSException + protected boolean commitTx(Session session) throws JMSException { - _logger.debug("protected void commitTx(Session session): called"); + log.debug("protected void commitTx(Session session): called"); + + boolean committed = false; - _logger.trace("Batch time reached"); + log.trace("Batch time reached"); if (_failAfterSend) { - _logger.trace("Batch size reached"); + log.trace("Batch size reached"); if (_failOnce) { _failAfterSend = false; } - _logger.trace("Failing After Send"); - doFailover(); + log.trace("Failing After Send"); + waitForUser(KILL_BROKER_PROMPT); } if (session.getTransacted()) @@ -1182,13 +1253,14 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _failBeforeCommit = false; } - _logger.trace("Failing Before Commit"); - doFailover(); + log.trace("Failing Before Commit"); + waitForUser(KILL_BROKER_PROMPT); } - long l = System.currentTimeMillis(); + long l = System.nanoTime(); session.commit(); - _logger.debug("Time taken to commit :" + (System.currentTimeMillis() - l) + " ms"); + committed = true; + log.debug("Time taken to commit :" + ((System.nanoTime() - l) / 1000000f) + " ms"); if (_failAfterCommit) { @@ -1197,84 +1269,56 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _failAfterCommit = false; } - _logger.trace("Failing After Commit"); - doFailover(); + log.trace("Failing After Commit"); + waitForUser(KILL_BROKER_PROMPT); } - _logger.trace("Session Commited."); + log.trace("Session Commited."); } catch (JMSException e) { - _logger.trace("JMSException on commit:" + e.getMessage(), e); + log.trace("JMSException on commit:" + e.getMessage(), e); // Warn that the bounce back client is not available. if (e.getLinkedException() instanceof AMQNoConsumersException) { - _logger.debug("No consumers on queue."); + log.debug("No consumers on queue."); } try { session.rollback(); - _logger.trace("Message rolled back."); + log.trace("Message rolled back."); } catch (JMSException jmse) { - _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); + log.trace("JMSE on rollback:" + jmse.getMessage(), jmse); // Both commit and rollback failed. Throw the rollback exception. throw jmse; } } } + + return committed; } /** - * Sends the message to the specified destination. If the destination is null, it gets sent to the default destination of - * the ping producer. If an explicit destination is set, this overrides the default. + * Outputs a prompt to the console and waits for the user to press return. * - * @param destination The destination to send to. - * @param message The message to send. - * - * @throws javax.jms.JMSException All underlying JMSExceptions are allowed to fall through. + * @param prompt The prompt to display on the console. */ - protected void sendMessage(Destination destination, Message message) throws JMSException + protected void waitForUser(String prompt) { - if (_failBeforeSend) - { - if (_failOnce) - { - _failBeforeSend = false; - } - - _logger.trace("Failing Before Send"); - doFailover(); - } - - if (destination == null) - { - _producer.send(message); - } - else - { - _producer.send(destination, message); - } - } + System.out.println(prompt); - /** - * Prompts the user to terminate the broker, in order to test failover functionality. This method will block until the - * user supplied some input on the terminal. - */ - protected void doFailover() - { - System.out.println("Kill Broker now then press return"); try { System.in.read(); } catch (IOException e) { - // ignore + // Ignored. } System.out.println("Continuing."); -- cgit v1.2.1 From 0370e5550e1d9bc72d742bbbee1f6f0e2835406e Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 5 Apr 2007 13:36:04 +0000 Subject: Merged revisions 525531-525536 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r525531 | rgreig | 2007-04-04 16:18:44 +0100 (Wed, 04 Apr 2007) | 1 line Added standard command line handline ........ r525533 | rgreig | 2007-04-04 16:19:38 +0100 (Wed, 04 Apr 2007) | 1 line Added simeple file copy function. ........ r525535 | rgreig | 2007-04-04 16:20:30 +0100 (Wed, 04 Apr 2007) | 1 line Added comments and logging to track down bug. ........ r525536 | rgreig | 2007-04-04 16:21:43 +0100 (Wed, 04 Apr 2007) | 1 line Fixed dangling transaction problem by correctly binding queue. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@525825 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/PingDurableClient.java | 5 +- .../apache/qpid/requestreply/PingPongProducer.java | 92 ++++++++++------------ 2 files changed, 44 insertions(+), 53 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java index 77526141d6..9439604acd 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java @@ -35,6 +35,7 @@ import javax.jms.Message; import org.apache.log4j.Logger; import org.apache.qpid.requestreply.PingPongProducer; +import org.apache.qpid.util.CommandLineParser; import uk.co.thebadgerset.junit.extensions.util.MathUtils; import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; @@ -71,6 +72,7 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; *

    uniqueDests false Prevents destination names being timestamped. *
    transacted true Only makes sense to test with transactions. *
    persistent true Only makes sense to test persistent. + *
    durableDests true Should use durable queues with persistent messages. *
    commitBatchSize 10 *
    rate 20 Total default test time is 5 seconds. *
    @@ -108,6 +110,7 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList defaults.setProperty(PERSISTENT_MODE_PROPNAME, "true"); defaults.setProperty(TX_BATCH_SIZE_PROPNAME, "10"); defaults.setProperty(RATE_PROPNAME, "20"); + defaults.setProperty(DURABLE_DESTS_PROPNAME, "true"); } /** Specifies the number of pings to send, if larger than 0. 0 means send until told to stop. */ @@ -150,7 +153,7 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList try { // Create a ping producer overriding its defaults with all options passed on the command line. - Properties options = processCommandLine(args); + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); PingDurableClient pingProducer = new PingDurableClient(options); // Create a shutdown hook to terminate the ping-pong producer. diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 44f7083bb5..913685bca2 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -35,13 +35,10 @@ import javax.jms.*; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQNoConsumersException; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.*; import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.jms.MessageProducer; import org.apache.qpid.jms.Session; import org.apache.qpid.url.URLSyntaxException; @@ -90,6 +87,7 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; *

    timeout 30000 In milliseconds. The timeout to stop waiting for replies. *
    commitBatchSize 1 The number of messages per transaction in transactional mode. *
    uniqueDests true Whether each receiver only listens to one ping destination or all. + *
    durableDests false Whether or not durable destinations are used. *
    ackMode AUTO_ACK The message acknowledgement mode. Possible values are: * 0 - SESSION_TRANSACTED * 1 - AUTO_ACKNOWLEDGE @@ -257,6 +255,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Defines the default value for the unique destinations property. */ public static final boolean UNIQUE_DESTS_DEFAULT = true; + public static final String DURABLE_DESTS_PROPNAME = "durableDests"; + public static final boolean DURABLE_DESTS_DEFAULT = false; + /** Holds the name of the proeprty to get the message acknowledgement mode from. */ public static final String ACK_MODE_PROPNAME = "ackMode"; @@ -299,6 +300,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT); defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT); defaults.setPropertyIfNull(UNIQUE_DESTS_PROPNAME, UNIQUE_DESTS_DEFAULT); + defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT); defaults.setPropertyIfNull(FAIL_BEFORE_COMMIT_PROPNAME, FAIL_BEFORE_COMMIT_DEFAULT); defaults.setPropertyIfNull(FAIL_AFTER_COMMIT_PROPNAME, FAIL_AFTER_COMMIT_DEFAULT); defaults.setPropertyIfNull(FAIL_BEFORE_SEND_PROPNAME, FAIL_BEFORE_SEND_DEFAULT); @@ -337,6 +339,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Flag used to indicate if the destinations should be unique client. */ protected boolean _isUnique; + /** Flag used to indicate that durable destination should be used. */ + protected boolean _isDurable; + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ protected boolean _failBeforeCommit; @@ -424,6 +429,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** The prompt to display when asking the user to kill the broker for failover testing. */ private static final String KILL_BROKER_PROMPT = "Kill broker now, then press Return."; + private String _clientID; /** * Creates a ping producer with the specified parameters, of which there are many. See the class level comments @@ -463,6 +469,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _rate = properties.getPropertyAsInteger(RATE_PROPNAME); _isPubSub = properties.getPropertyAsBoolean(PUBSUB_PROPNAME); _isUnique = properties.getPropertyAsBoolean(UNIQUE_DESTS_PROPNAME); + _isDurable = properties.getPropertyAsBoolean(DURABLE_DESTS_PROPNAME); _ackMode = properties.getPropertyAsInteger(ACK_MODE_PROPNAME); _pauseBatch = properties.getPropertyAsLong(PAUSE_AFTER_BATCH_PROPNAME); @@ -498,10 +505,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Generate a unique identifying name for this client, based on it ip address and the current time. InetAddress address = InetAddress.getLocalHost(); - String clientID = address.getHostName() + System.currentTimeMillis(); + _clientID = address.getHostName() + System.currentTimeMillis(); // Create a connection to the broker. - createConnection(clientID); + createConnection(_clientID); // Create transactional or non-transactional sessions, based on the command line arguments. _producerSession = (Session) getConnection().createSession(_transacted, _ackMode); @@ -509,7 +516,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Create the destinations to send pings to and receive replies from. _replyDestination = _consumerSession.createTemporaryQueue(); - createPingDestinations(_noOfDestinations, _selector, _destinationName, _isUnique); + createPingDestinations(_noOfDestinations, _selector, _destinationName, _isUnique, _isDurable); // Create the message producer only if instructed to. if (producer) @@ -548,7 +555,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { try { - Properties options = processCommandLine(args); + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); // Create a ping producer overriding its defaults with all options passed on the command line. PingPongProducer pingProducer = new PingPongProducer(options); @@ -576,43 +583,6 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } } - /** - * Extracts all name=value pairs from the command line, sets them all as system properties and also returns - * a map of properties containing them. - * - * @param args The command line. - * - * @return A set of properties containing all name=value pairs from the command line. - * - * @todo This is a commonly used piece of code. Make it accept a command line definition and move it into the - * CommandLineParser class. - */ - protected static Properties processCommandLine(String[] args) - { - // Use the command line parser to evaluate the command line. - CommandLineParser commandLine = new CommandLineParser(new String[][] {}); - - // Capture the command line arguments or display errors and correct usage and then exit. - Properties options = null; - - try - { - options = commandLine.parseCommandLine(args); - - // Add all the trailing command line options (name=value pairs) to system properties. Tests may pick up - // overridden values from there. - commandLine.addCommandLineToSysProperties(); - } - catch (IllegalArgumentException e) - { - System.out.println(commandLine.getErrors()); - System.out.println(commandLine.getUsage()); - System.exit(1); - } - - return options; - } - /** * Convenience method for a short pause. * @@ -677,11 +647,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * * @throws JMSException Any JMSExceptions are allowed to fall through. */ - public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique) - throws JMSException + public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique, + boolean durable) throws JMSException, AMQException { log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " - + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + "): called"); + + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = " + + durable + "): called"); _pingDestinations = new ArrayList(); @@ -709,13 +680,30 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Check if this is a pub/sub pinger, in which case create topics. if (_isPubSub) { - destination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id); - log.debug("Created topic " + destination); + if (!durable) + { + destination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id); + log.debug("Created non-durable topic " + destination); + } + else + { + destination = + AMQTopic.createDurableTopic(new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id), + _clientID, (AMQConnection) _connection); + log.debug("Created durable topic " + destination); + } } // Otherwise this is a p2p pinger, in which case create queues. else { - destination = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, rootName + id); + AMQShortString destinationName = new AMQShortString(rootName + id); + destination = + new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, destinationName, destinationName, false, false, + _isDurable); + ((AMQSession) _producerSession).createQueue(destinationName, false, _isDurable, false); + ((AMQSession) _producerSession).bindQueue(destinationName, destinationName, null, + ExchangeDefaults.DIRECT_EXCHANGE_NAME); + log.debug("Created queue " + destination); } -- cgit v1.2.1 From 70504ccb1387800c27dd4608c1dd387a912e342a Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Mon, 9 Apr 2007 09:37:54 +0000 Subject: Added shell script. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@526689 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/PingDurableClient.java | 41 ++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java index 9439604acd..82e43e542f 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java @@ -58,10 +58,11 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; * additionally accepts the following parameters: * *

    - *
    Parameters
    Parameter Default Comments - *
    numMessages 100 The total number of messages to send. - *
    duration 30S The length of time to ping for. (Format dDhHmMsS, for d days, h hours, - * m minutes and s seconds). + *
    Parameter Default Comments + *
    numMessages 100 The total number of messages to send. + *
    numMessagesToAction -1 The number of messages to send before taking a custom 'action'. + *
    duration 30S The length of time to ping for. (Format dDhHmMsS, for d days, h hours, + * m minutes and s seconds). *
    * *

    This ping client also overrides some of the defaults of its parent class, to provide a reasonable set up @@ -81,12 +82,18 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; * is reached. Reaching the limit will be interpreted as the first signal to stop sending, and the ping client will * wait for the second signal before receiving its pings. * + *

    This class provides a mechanism for extensions to add arbitrary actions, after a particular number of messages + * have been sent. When the number of messages equal the value set in the 'numMessagesToAction' property is method, + * the {@link #takeAction} method is called. By default this does nothing, but extensions of this class can provide + * custom behaviour with alternative implementations of this method (for example taking a backup). + * *

    *
    CRC Card
    Responsibilities Collaborations *
    Send and receive pings. *
    Accept user input to signal stop sending. *
    Accept user input to signal start receiving. *
    Provide feedback on pings sent versus pings received. + *
    Provide extension point for arbitrary action on a particular message count. *
    */ public class PingDurableClient extends PingPongProducer implements ExceptionListener @@ -97,6 +104,8 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList public static final String NUM_MESSAGES_DEFAULT = "100"; public static final String DURATION_PROPNAME = "duration"; public static final String DURATION_DEFAULT = "30S"; + public static final String NUM_MESSAGES_TO_ACTION_PROPNAME = "numMessagesToAction"; + public static final String NUM_MESSAGES_TO_ACTION_DEFAULT = "-1"; /** The maximum length of time to wait whilst receiving pings before assuming that no more are coming. */ private static final long TIME_OUT = 3000; @@ -111,11 +120,15 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList defaults.setProperty(TX_BATCH_SIZE_PROPNAME, "10"); defaults.setProperty(RATE_PROPNAME, "20"); defaults.setProperty(DURABLE_DESTS_PROPNAME, "true"); + defaults.setProperty(NUM_MESSAGES_TO_ACTION_PROPNAME, NUM_MESSAGES_TO_ACTION_DEFAULT); } /** Specifies the number of pings to send, if larger than 0. 0 means send until told to stop. */ private int numMessages; + /** Holds the number of messages to send before taking triggering the action. */ + private int numMessagesToAction; + /** Sepcifies how long to ping for, if larger than 0. 0 means send until told to stop. */ private long duration; @@ -136,6 +149,7 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList numMessages = properties.getPropertyAsInteger(NUM_MESSAGES_PROPNAME); String durationSpec = properties.getProperty(DURATION_PROPNAME); + numMessagesToAction = properties.getPropertyAsInteger(NUM_MESSAGES_TO_ACTION_PROPNAME); if (durationSpec != null) { @@ -180,7 +194,7 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList /** * Performs the main test procedure implemented by this ping client. See the class level comment for details. */ - public int send() throws Exception + protected int send() throws Exception { log.debug("public void sendWaitReceive(): called"); @@ -245,6 +259,14 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList _publish = false; } + // Perform the arbitrary action if the number of messages sent has reached the right number. + if (messagesSent == numMessagesToAction) + { + System.out.println("At action point, Messages sent = " + messagesSent + ", Messages Committed = " + + messagesCommitted + ", Messages not Committed = " + messagesNotCommitted); + takeAction(); + } + // Determine if the end condition has been met, based on the number of messages, time passed, errors on // the connection or user input. long now = System.nanoTime(); @@ -293,7 +315,7 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList return messagesSent; } - private void receive(int messagesSent) throws Exception + protected void receive(int messagesSent) throws Exception { // Re-establish the connection and the message consumer. _queueJVMSequenceID = new AtomicInteger(); @@ -389,4 +411,11 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList } }); } + + /** + * Performs an aribtrary action once the 'numMesagesToAction' count is reached on sending messages. This default + * implementation does nothing. + */ + public void takeAction() + { } } -- cgit v1.2.1 From ffe5e29f94b376c6f5900b2f9577c8bbaef7407b Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Thu, 19 Apr 2007 16:24:30 +0000 Subject: Merged revisions 1-447993,447995-448007,448009-448141,448143-448157,448161-448194,448196-448210,448212-448218,448220-448223,448225-448233,448235,448237-448241,448243-448596,448598-448623,448625-448850,448852-448880,448882-448982,448984-449635,449637-449639,449641-449642,449644-449645,449647-449674,449676-449719,449721-449749,449751-449762,449764-449933,449935-449941,449943-450383,450385,450387-450400,450402-450433,450435-450503,450505-450555,450557-450860,450862-451024,451026-451149,451151-451316,451318-451931,451933-452139,452141-452162,452164-452320,452322,452324-452325,452327-452333,452335-452429,452431-452528,452530-452545,452547-453192,453194-453195,453197-453536,453538,453540-453656,453658-454676,454678-454735,454737,454739-454781,454783-462728,462730-462819,462821-462833,462835-462839,462841-463071,463073-463178,463180-463308,463310-463362,463364-463375,463377-463396,463398-463402,463404-463409,463411-463661,463663-463670,463672-463673,463675-464493,464495-464502,464504-464576,464578-464613,464615-464628,464630,464632-464866,464868-464899,464901-464942,464944-464949,464951-465004,465006-465016,465018-465053,465055-465165,465167-465321,465323-465406,465408-465427,465429-465431,465433-465548,465550-466044,466047-466075,466077,466079-466081,466083-466099,466101-466112,466114-466126,466128-466240,466242-466971,466973-466978,466980-467309,467311-467312,467316-467328,467330-467485,467487-467588,467590-467604,467606-467699,467701-467706,467708-467749,467751-468069,468071-468537,468539-469241,469244-469246,469248-469318,469320-469421,469423,469425-469429,469431-469435,469437-469462,469464-469469,469472-469477,469479-469490,469492-469503,469505-469529,469531-469598,469600-469624,469626-469737,469739-469752,469754-469806,469808-469928,469930-469953,469955-470011,470013-470109,470111-470335,470338-470339,470341-470379,470381,470383-470399,470401-470446,470448-470741,470743-470758,470760-470809,470811-470817,470819-470993,470995-471001,471003-471788,471790-471792,471794-472028,472030-472032,472034-472036,472038,472040,472043,472045-472059,472061,472063,472065-472066,472068,472070-472072,472074-472080,472082,472084-472092,472094-472107,472109-472123,472125-472158,472160-472165,472167-472172,472174-472457,472459-472460,472462-472464,472466-472470,472472-472483,472486-472491,472493-472494,472496-472497,472499,472501-472503,472505-472512,472514-472544,472546-472556,472558-472560,472562-472572,472574-472587,472589-472591,472593-472605,472607,472609-472731,472733-472786,472788-472843,472845-472849,472851-472859,472861-472878,472880-472903,472905,472907-472988,472990-472991,472993-473071,473073-473086,473088-473090,473093,473095-473096,473098-473106,473108-473110,473112-473185,473187-473260,473262,473268-473270,473275-473279,473281,473284-473287,473289-473295,473297-473306,473308-473330,473332-473335,473337,473339-473344,473346-473351,473353-473355,473357-473358,473361-473471,473473-473497,473499-473535,473537-473567,473569-473888,473890-474451,474454-474492,474494-474563,474565-474843,474845-474865,474867-474932,474934-475035,475037-475144,475146-475180,475182-475265,475267-475285,475287,475289-475293,475295-475296,475298-475302,475304-475631,475633-475649,475651-475748,475750-475752,475754-476107,476109-476302,476304-476413,476415-476430,476432-476700,476702-476868,476870-477147,477149-477213,477215-477263,477265-477340,477342-477635,477637-477789,477791-477825,477827-477841,477843,477846-477852,477854,477856,477858-477865,477867-477894,477896-478022,478024-478182,478184-478211,478213-478233,478235-478236,478238-478241,478243-478252,478254-478259,478261-478263,478265,478267-478269,478271-478286,478288-478342,478344-478379,478381-478412,478414-478443,478445-478636,478639-478658,478660-478821,478823-478853,478855-478922,478924-478962,478965-478974,478976-479029,479031-479049,479051-479210,479212-479214,479216-479407,479409-479415,479417-479425,479427-479559,479561-479639,479641-479676,479678-479685,479687-480030,480033-480086,480091-480093,480095-480118,480120-480139,480141,480143-480148,480150-480156,480158-480163,480165-480177,480179-480189,480191-480193,480195-480198,480200-480220,480222-480282,480284-480292,480294-480308,480310-480317,480320-480422,480424,480426-480581,480583-480656,480658-480692,480695-480702,480704,480706-480710,480712-480910,480913-480933,480935-480945,480947-480972,480974-480993,480995-481034,481036-481158,481161-481174,481176-481220,481222-481234,481236-481260,481263-481264,481266-481296,481298-481304,481306-481311,481313-481332,481334,481336-481380,481382-481441,481443-482144,482146-482180,482182-482193,482195-482232,482234-482236,482239,482241-482242,482244-482247,482250-482251,482253,482256-482261,482264-482288,482290-482364,482366,482368,482370-482554,482556,482558-482569,482572-482636,482638,482640-482696,482698-482722,482724-482732,482734-482771,482774-482957,482959-483045,483047-483105,483108,483110-483115,483117,483119-483127,483130-483134,483136-483148,483150-483158,483160-483164,483166-483178,483180-483391,483393-483400,483402-483403,483405-483418,483420-483421,483425-483436,483438-483470,483472-483502,483504-483558,483560-483599,483601-483637,483639-483644,483646-483659,483661-483670,483672-483878,483880-483910,483912-483915,483917-483940,483942,483944-483968,483970-483972,483974-483976,483978,483980-484612,484614-484657,484659-484693,484695-484718,484720-484842,484844-484847,484849-484986,484988-485019,485021-485489,485491-485544,485546-485591,485593,485595-485697,485699-485729,485731-485734,485736-485779,485781-485787,485789-485851,485853,485855-486007,486009,486011-486020,486022-486083,486085-486097,486099-486117,486120-486131,486133-486148,486150-486161,486163-486164,486166-486197,486199-486205,486208-486247,486249-486253,486256-486427,486429-486431,486433-486554,486556-486573,486575-486593,486595,486597-486609,486611-486619,486622,486625,486627-486641,486643-486645,486649-486687,486689-486721,486723-486730,486732-486746,486748-486759,486761,486763-486777,486779-486782,486784-486788,486790,486792,486794-486796,486798-487175,487178,487180-487213,487215,487217-487267,487269-487284,487286-487298,487300-487358,487360-487367,487369-487382,487384-487434,487436-487480,487482-487547,487549-487561,487563-487565,487567-487578,487580-487615,487617-487622,487624,487626,487628,487630-487635,487637-487703,487705-487777,487780-487781,487783-487800,487802-487803,487805-487820,487822-487848,487850-487902,487904-488103,488105-488133,488135-488158,488160-488163,488165-488187,488189-488216,488218-488248,488250-488278,488280,488282-488303,488305-488313,488315-488342,488344-488351,488353-488376,488378-488449,488451-488593,488595,488597-488623,488625-488700,488702-488704,488706-488710,488714,488716-488725,488727-488744,488746-488770,488772-488798,488800,488802-488807,488809,488811-488829,488831-488843,488845-488851,488853-489069,489071-489077,489079-489081,489084-489102,489104-489105,489107-489109,489111-489112,489114-489139,489141-489178,489181-489203,489205-489211,489213,489216-489329,489332-489402,489404-489417,489419-489421,489423-489643,489645-489690,489692-489703,489705-489714,489716-489747,489749-489753,489755-489803,489805-489904,489906-490372,490374-490504,490506-490604,490606-490707,490710-490733,490735-490871,490873-490984,490986-491028,491030,491032-491071,491073-491119,491121-491576,491578-491672,491674-491800,491802-491838,491840-491878,491880-492183,492185-492279,492281-492317,492319-492513,492515-492584,492586-492587,492589-492601,492603-492635,492637-492640,492642-492717,492719-492723,492725-492729,492731-492755,492757-492901,492903-492955,492957-492962,492964-492997,492999-493002,493004-493041,493043-493059,493062-493063,493065-493086,493088-493125,493127-493139,493141-493150,493152-493871,493873-494017,494019-494030,494032-494041,494043-494091,494093-494120,494122-494354,494356-494436,494438-494539,494541-494552,494554-494586,494588-494649,494651,494653-494654,494656-494657,494659-494764,494766-494768,494770-494796,494798-494799,494802,494804-494860,494862-494903,494905-494906,494908-495019,495021-495160,495162-495168,495171-495188,495190-495229,495231-495254,495256-495303,495305-495313,495315-495336,495338-495372,495374-495379,495381-495454,495457-495459,495462-495516,495518-495524,495526-495531,495533-495548,495551-495553,495555,495557-495558,495560,495562-495573,495575-495583,495585-495594,495596-495628,495630-495638,495640-495651,495653-495660,495662-495753,495755-496259,496261-496262,496264-496269,496271-496275,496277-496301,496303-496316,496318-496383,496385-496413,496415-496495,496497-496625,496627-496636,496638-496640,496642-496647,496650-496657,496659-496660,496663-496664,496666-496677,496679-496681,496683-496730,496732-496750,496752,496754-496784,496786-496832,496834-496840,496842-496990,496992-496995,496997-497340,497343-497351,497353-497403,497405-497424,497426-497438,497440-497481,497483-497497,497499-497765,497767-497769,497771-497775,497777-497778,497780,497782-497783,497785,497787-497812,497814-497871,497873-497877,497879-498573,498575-498588,498590,498592,498594-498636,498638-498669,498671-498686,498688-498689,498691-498719,498721-498964,498966-498969,498971-498973,498975-498982,498985-499035,499037-499040,499042,499044-499048,499050-499082,499084-499086,499088-499164,499167-499169,499171-499355,499357-499370,499372-499373,499375-499391,499393,499395-499425,499428,499430-499445,499447-499455,499457-499460,499462-499465,499467,499469-499489,499491-499492,499494-499531,499533-499562,499566-499627,499629-499715,499717-499732,499734-499755,499758-499763,499765-499780,499782-499795,499797-499802,499804-499844,499846,499848-499850,499852-499863,499865-499873,499875-499974,499976-499978,499980-500263,500265-500283,500285-500309,500311-501000,501002,501012-501057,501059-501095,501097-501390,501392-501410,501413-501447,501449-501454,501456,501458-501464,501466-501471,501473-501803,501805-501913,501915-501916,501918-501919,501921-501944,501946-502171,502173-502177,502181,502183-502247,502250-502252,502254-502260,502262-502267,502270,502272,502274-502575,502577-502609,502611-502619,502621-502626,502628-502654,502656-503592,503594-503603,503605-503608,503610-503636,503638-503645,503647-503705,503707-503789,503791-504024,504026-504111,504113-504506,504508-504735,504737-504863,504865-504867,504869-504914,504916-505241,505243-505254,505257-505267,505269-505354,505356-505891,505893-505971,505973-506400,506402-506404,506407-506438,506440-506516,506518-506541,506543-506966,506968-506971,506973-507095,507097-507108,507111-507454,507456,507459-507471,507473-507556,507558,507560-507581,507585-507594,507597,507599-507608,507610-507728,507730-507893,507895-507937,507940-508234,508236-508350,508352-508365,508367-508380,508383,508386-508415,508417-508648,508650-508941,508943-509146,509148-509171,509173-509175,509179-509201,509203-509207,509209-509215,509217-509222,509224-509477,509480-509627,509629-509634,509636-509641,509643-509736,509738-509931,509933-510059,510061-510075,510077-510158,510161-510896,510898-510938,510940-511388,511390-511922,511924-512287,512289-512698,512702-512813,512815-512817,512819-513359,513361-513370,513372-514702,514704-514886,514888-514902,514904-515126,515129-515141,515143-515516,515518-515534,515536-515538,515540-515648,515650-515651,515653-516070,516072-516411,516413-516448,516450,516452-517637,517639-517647,517649-517659,517661-517663,517665-517677,517679-517682,517684-517744,517746-518085,518087-518175,518177-518558,518560-518568,518571-518666,518668,518670-518699,518701-518987,518990-518992,518994-519908,519910-519932,519934-520414,520416-520842,520844-520937,520939-521362,521364-521792,521794-522462,522464-522527,522529-522534,522536-522566,522568-522993,522995-523244,523246-525530,525532,525534,525537-526149,526151-526682,526686-526713,526715-530399 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r521682 | bhupendrab | 2007-03-23 11:50:55 +0000 (Fri, 23 Mar 2007) | 2 lines QPID-418 (merged from trunk) svn merge -r521336:521345 https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid/java . ........ r521705 | rgreig | 2007-03-23 12:44:14 +0000 (Fri, 23 Mar 2007) | 1 line Updates to performance tests. ........ r521710 | ritchiem | 2007-03-23 12:59:18 +0000 (Fri, 23 Mar 2007) | 2 lines QPID-419 Access Control QPID-423 Authentication per virtualhost Improved error handling when hostconfig is not specifed. Was NPE-ing ........ r521715 | ritchiem | 2007-03-23 13:10:33 +0000 (Fri, 23 Mar 2007) | 2 lines QPID-423 Authentication per virtualhost Improved error handling when hostconfig is not specifed. Was NPE-ing ........ r521782 | bhupendrab | 2007-03-23 16:02:51 +0000 (Fri, 23 Mar 2007) | 1 line QPID-420 (merged from trunk) And r518998:518999 and r520846:520850 ........ r522959 | ritchiem | 2007-03-27 16:39:51 +0100 (Tue, 27 Mar 2007) | 2 lines Updated assembly/bin.xml to include transient_config.xml persistent_config.xml ........ r522961 | ritchiem | 2007-03-27 16:42:40 +0100 (Tue, 27 Mar 2007) | 1 line forgot to rename files after they had been copied ........ r522967 | ritchiem | 2007-03-27 16:56:03 +0100 (Tue, 27 Mar 2007) | 1 line correctly renamed transient and persistent config files ........ r522977 | ritchiem | 2007-03-27 17:06:15 +0100 (Tue, 27 Mar 2007) | 1 line updated config files ........ r522981 | ritchiem | 2007-03-27 17:10:45 +0100 (Tue, 27 Mar 2007) | 1 line Added echo of progress and reduced timeout ........ r522989 | ritchiem | 2007-03-27 17:33:04 +0100 (Tue, 27 Mar 2007) | 1 line fixed error where script wouldn't pickup running pids ........ r522990 | ritchiem | 2007-03-27 17:36:34 +0100 (Tue, 27 Mar 2007) | 1 line Added additional logging and comments ........ r522991 | ritchiem | 2007-03-27 17:37:17 +0100 (Tue, 27 Mar 2007) | 1 line Added additional comments ........ r523747 | rajith | 2007-03-29 16:32:56 +0100 (Thu, 29 Mar 2007) | 1 line Fix for setting the message id ........ r524050 | rgreig | 2007-03-30 12:51:09 +0100 (Fri, 30 Mar 2007) | 1 line Removed excess logging to optimize performance. ........ r524739 | ritchiem | 2007-04-02 08:29:06 +0100 (Mon, 02 Apr 2007) | 1 line Added BDB Test scripts and updated pom to contain same tests as were used in perftesting ........ r524740 | ritchiem | 2007-04-02 08:47:29 +0100 (Mon, 02 Apr 2007) | 1 line Fixed error with passwordfile parameter ........ r524743 | ritchiem | 2007-04-02 09:07:55 +0100 (Mon, 02 Apr 2007) | 1 line Added CTQ tests ........ r524763 | ritchiem | 2007-04-02 11:50:06 +0100 (Mon, 02 Apr 2007) | 1 line Added verify password method to PrincipalDatabase ........ r524765 | ritchiem | 2007-04-02 11:55:12 +0100 (Mon, 02 Apr 2007) | 1 line Moved broker details to a separate variable. ........ r524767 | ritchiem | 2007-04-02 12:17:54 +0100 (Mon, 02 Apr 2007) | 1 line ignored idea files ........ r525487 | ritchiem | 2007-04-04 11:42:59 +0100 (Wed, 04 Apr 2007) | 3 lines Added default timeout to AMQConnection.close(); ........ r525553 | ritchiem | 2007-04-04 17:34:35 +0100 (Wed, 04 Apr 2007) | 1 line Updated case of properties ........ r525766 | ritchiem | 2007-04-05 09:51:55 +0100 (Thu, 05 Apr 2007) | 1 line QPID-308 Added test case to demonstrate heap exhaustion of broker. Can't be run InVM as it kills the broker. ........ r525777 | ritchiem | 2007-04-05 10:29:22 +0100 (Thu, 05 Apr 2007) | 20 lines QPID-414 : Addition of CRAM-MD5-HASHED authentication. Same as CRAM-MD5 but the client uses the hash of the password rather than the original password. This allows the broker to store the hash not the original password. Added initial tool for generation passwords. Broker: Renamed MD5PasswordFilePrincipalDatabase.java to Base64MD5PasswordFilePrincipalDatabase.java as that more accurately represents the file contents. PlainPasswordVhostFilePrincipalDatabase.java - import tidy up PrincipalDatabaseAuthenticationManager.java - Changed to add our SASL providers at the start of the SASL list. CRAMMD5Hashed* - New SASL mechanism that delegates to CRAM-MD5 but understands that the password to use is the hash of the users password. JCAProvider - Removed the addProvider() line as this is done after the construction in PrincipalDatabaseAuthenticationManager. PlainSaslServerFactory - White Space Passwd.java - New util stub for managing passwords ala htpasswd. Client Added CRAM-MD5-HASHED to CallbackHandlerRegistry Added ClientFactory for CRAMMD5Hashed that returns the first CRAM-MD5 SaslClient. DynamicSaslRegistrar.java - Tidied imports added new JCAProviders at the start of the Sasl lists. DynamicSaslRegistrar.properties - Added CRAM-MD5-HASHED handler. JCAProvider.java - as with broker stopped JCAProvider.java adding itself as the DynamicSaslRegistrar.java does this on the client. UsernameHashedPasswordCallbackHandler.java - New callback handler that is used by CRAM-MD5-HASHED. It hashes the client's password and uses that in the CRAM-MD5 algorithm. ........ r525785 | ritchiem | 2007-04-05 10:48:43 +0100 (Thu, 05 Apr 2007) | 1 line Old ant folder ........ r525786 | ritchiem | 2007-04-05 10:57:33 +0100 (Thu, 05 Apr 2007) | 1 line QPID-440 - added comments in the code relating to this bug. ........ r525787 | ritchiem | 2007-04-05 10:58:20 +0100 (Thu, 05 Apr 2007) | 2 lines QPID-308 removed closeConnection() that calls close(-1) and may result in a client hang. better to call closeConnection(long timeout) so forced this my removing closeConnection(); ........ r525788 | ritchiem | 2007-04-05 11:00:56 +0100 (Thu, 05 Apr 2007) | 1 line QPID-414 update to config.xml to give usage example. ........ r525804 | ritchiem | 2007-04-05 13:19:31 +0100 (Thu, 05 Apr 2007) | 1 line QPID-308 Updated HeapExhaustion to be able to be run from command line ........ r525817 | ritchiem | 2007-04-05 14:14:50 +0100 (Thu, 05 Apr 2007) | 1 line Update to qpid stop scripts to properly check for existing broker instances and promptly stop them. ........ r525829 | ritchiem | 2007-04-05 14:50:56 +0100 (Thu, 05 Apr 2007) | 1 line Updated scripts to work correctly under solaris and bash 2.0 ........ r525862 | rgodfrey | 2007-04-05 17:37:40 +0100 (Thu, 05 Apr 2007) | 1 line QPID-443 : Fix to transactionality of message publishing ........ r525867 | ritchiem | 2007-04-05 17:47:59 +0100 (Thu, 05 Apr 2007) | 2 lines QPID-416 Provided simple update to Access Control via FileAccessManager to allow access rights for a virtualhost to be stored in a separate file. Updated PrincipalDatabaseAccessManager to use the default AccessManager if the specified PrincipalDatabase is not an AccessManager. ........ r526091 | ritchiem | 2007-04-06 09:21:01 +0100 (Fri, 06 Apr 2007) | 5 lines QPID-416 Update to Access control to allow simply read/write permissions per Virtual host. access - updated file to have examples of access control. AccessManager - Deprecated old isAuthorised method Implemented new isAuthorized method on all AccessManagers ........ r526113 | ritchiem | 2007-04-06 11:28:43 +0100 (Fri, 06 Apr 2007) | 1 line Updated case of properties to be true cammelCase and updated tests to run for a duration of 10 minutes rather than set message count. To provide better results for graphing. ........ r526117 | ritchiem | 2007-04-06 11:42:11 +0100 (Fri, 06 Apr 2007) | 9 lines QPID-416 Update to Access control to allow simply read/write permissions per Virtual host. access - updated file to have examples of access control. Changed AMQProtocolSession to record an authorized Principal not just a String. - Required Added AccessRights files needed for VirtualHostAccess control. Updated ConnectionOpenMethodHandler to allow Principals with any access to connect not just read. UsernamePrincipal - Added a toString ........ r526118 | rgodfrey | 2007-04-06 11:55:17 +0100 (Fri, 06 Apr 2007) | 1 line ........ r526122 | ritchiem | 2007-04-06 12:26:06 +0100 (Fri, 06 Apr 2007) | 1 line removed pauses between batches ........ r526154 | rgodfrey | 2007-04-06 14:24:46 +0100 (Fri, 06 Apr 2007) | 1 line QPID-443 : Fix to transactionality of message publishing ........ r526157 | bhupendrab | 2007-04-06 14:32:56 +0100 (Fri, 06 Apr 2007) | 1 line QPID-444 : Enabling the Qpid to use SASL. jmxmp can be plugged into for SASL. Can be configured to use security. ........ r526158 | ritchiem | 2007-04-06 14:34:52 +0100 (Fri, 06 Apr 2007) | 1 line Duplicate of BDB-Qpid.sh ........ r526159 | bhupendrab | 2007-04-06 14:37:47 +0100 (Fri, 06 Apr 2007) | 1 line QPID-444 : adding jmxport, which is used when out of the box JMXAgent is not used ........ r526166 | ritchiem | 2007-04-06 14:51:41 +0100 (Fri, 06 Apr 2007) | 1 line QPID-414 - Initial script to run the passwd gen. ........ r526187 | bhupendrab | 2007-04-06 15:53:36 +0100 (Fri, 06 Apr 2007) | 2 lines QPID-444 : Enabling the SASL support. jmxmp can be plugged into for SASL. ........ r526194 | rgreig | 2007-04-06 16:21:19 +0100 (Fri, 06 Apr 2007) | 1 line Added some ramping up performance tests. ........ r526195 | marnie | 2007-04-06 16:21:33 +0100 (Fri, 06 Apr 2007) | 1 line QPID-381 Amended session constructor to be non-transactional and use client ack mode. ........ r526198 | rgreig | 2007-04-06 16:26:02 +0100 (Fri, 06 Apr 2007) | 1 line Fixed message sizes. ........ r526199 | rgreig | 2007-04-06 16:29:06 +0100 (Fri, 06 Apr 2007) | 1 line Fixed commit batch size. ........ r526666 | ritchiem | 2007-04-09 08:47:14 +0100 (Mon, 09 Apr 2007) | 1 line Updated so the FileAppender includes time stamps by default.. ConversionPattern made the same as STDOUT and RollingFileAppender ........ r526691 | ritchiem | 2007-04-09 10:39:47 +0100 (Mon, 09 Apr 2007) | 1 line Added $@ to allow pass through of command line args to each sub process ........ r526692 | bhupendrab | 2007-04-09 10:45:06 +0100 (Mon, 09 Apr 2007) | 4 lines QPID-444 : added log statements and some config parameters. Removed the autoDelete parameter from createNewQueue method used from Management Console. ........ r526694 | bhupendrab | 2007-04-09 10:51:46 +0100 (Mon, 09 Apr 2007) | 1 line ........ r526709 | bhupendrab | 2007-04-09 12:02:08 +0100 (Mon, 09 Apr 2007) | 2 lines QPID-444 : updated the management console dependency configuration for sasl support ........ r526776 | rgreig | 2007-04-09 16:26:04 +0100 (Mon, 09 Apr 2007) | 1 line Stopped throwing away exception causes. ........ r526803 | rgreig | 2007-04-09 17:09:24 +0100 (Mon, 09 Apr 2007) | 1 line Got rid of some uses of System.out instead of log4j logging. ........ r526807 | rgreig | 2007-04-09 17:12:49 +0100 (Mon, 09 Apr 2007) | 1 line Got rid of some uses of System.out instead of log4j logging. ........ r527049 | ritchiem | 2007-04-10 08:58:26 +0100 (Tue, 10 Apr 2007) | 1 line Moved bdb tests to bdbstore package ........ r527050 | ritchiem | 2007-04-10 09:00:42 +0100 (Tue, 10 Apr 2007) | 1 line QueueDeclareHandler.java - Added more detail to error messages. Such as returning the queue name that was attempted to be declared but failed. ........ r527053 | ritchiem | 2007-04-10 09:03:15 +0100 (Tue, 10 Apr 2007) | 1 line Added a test to check that Persistent Queues do actually persist. ........ r527182 | ritchiem | 2007-04-10 17:29:47 +0100 (Tue, 10 Apr 2007) | 1 line QPID-446 Initial MBean framework. ........ r527487 | ritchiem | 2007-04-11 14:31:18 +0100 (Wed, 11 Apr 2007) | 5 lines QPID-446 AMQUserManagementMBean Initial implementation of user management in authentication file. UserManagement - Added annotations for MBeanOperations PrincipalDatabase - Added new methods to update,create,delete Principal. - Implemented method on all PrincipalDatabase implementations, most return false to say not complete except Base64MD5PasswordFilePrincipalDatabase - which now stores in memory the password file and flushes any changes to disk. ........ r527493 | ritchiem | 2007-04-11 14:50:40 +0100 (Wed, 11 Apr 2007) | 1 line QPID-446 Missed the commit of JMXManagedObjectRegistry change on verifyPassword char[] to String ........ r527499 | bhupendrab | 2007-04-11 15:16:02 +0100 (Wed, 11 Apr 2007) | 1 line QPID-444 : added CRAM-MD5-HASHED mechanism for sasl ........ r527509 | bhupendrab | 2007-04-11 15:47:22 +0100 (Wed, 11 Apr 2007) | 1 line ........ r527518 | ritchiem | 2007-04-11 16:21:37 +0100 (Wed, 11 Apr 2007) | 14 lines QPID-446 JMXManagedObjectRegistry - Split instantiation from starting up. To all the setting of the Access file when loaded later in the startup sequence. ManagedObjectRegistry - Added Start method MBeanInvocationHandlerImpl - Updated to allow the setting of the access properties object from the AMQUserManagementMBean NoopManagedObjectRegistry - implemented no-op start ConfigurationFileApplicationRegistry - Adjusted to split creation of ManagedObjectRegistry from starting server to allow the setting of access rights. AMQUserManagementMBean - Implemented reading of access rights file. Base64MD5PasswordFilePrincipalDatabase - added comment for future Management. PrincipalDatabaseManager - added initialiseManagement method ConfigurationFilePrincipalDatabaseManager - implemented general Management initialisation. PropertiesPrincipalDatabaseManager - no-op implementation ........ r527537 | ritchiem | 2007-04-11 16:47:30 +0100 (Wed, 11 Apr 2007) | 2 lines QPID-446 Update to contain jmx config settings. ........ r527556 | bhupendrab | 2007-04-11 17:07:58 +0100 (Wed, 11 Apr 2007) | 1 line synchronized with hash mechanism used in Broker ........ r527557 | ritchiem | 2007-04-11 17:08:54 +0100 (Wed, 11 Apr 2007) | 1 line Fixed Bug in convertPassword where data wasn't correctly updated PropertiesPrincipalDatabase, ........ r527558 | ritchiem | 2007-04-11 17:09:54 +0100 (Wed, 11 Apr 2007) | 1 line QpiQPID-446 Update to ensure qpid.password file is correctly written in savePasswordFile ........ r527803 | ritchiem | 2007-04-12 08:16:54 +0100 (Thu, 12 Apr 2007) | 5 lines QPID-446 Update to write accessRights file and correctly write Base64 MD5 Hashed password to password file. MBeanInvocationHandlerImpl - made statics ADMIN,READONLY,READWRITE public so they can be used in writing the access file. AMQUserManagementMBean - Update to write the access File. PrincipalDatabase - create getUser(username) to retrieve a Principal from the database this is then implemented in all PDs. Used to check for existence of a user. ........ r527843 | ritchiem | 2007-04-12 09:52:19 +0100 (Thu, 12 Apr 2007) | 10 lines QPID-446 Update to send userList to JMX Management console. Currently niave implementation just sending ALL users in one go. If a LDAPPrincipalDatabase was created this could be quite a lot of data a) to send but b) to create in broker Heap. PrincipalDatabase - javadoc'd and getUsers method, -changed verifyPassword method to take String for username rather than Principal only the Managment Console uses this method and it the MC should be changed to use the Broker SASL modules directly rather than having very similar ones of its own. - Removed AccountNotFound exception from createPrincipal as it made no sence No-op implementation in PlainPasswordFilePrincipalDatabase and PropertiesPrincipalDatabase Base64MD5PasswordFilePrincipalDatabase changed local User class to implement Principal so current Map can be returned via getUsers - Added locking to ensure integrity of files in the face of multiple edits. ........ r527848 | ritchiem | 2007-04-12 10:11:19 +0100 (Thu, 12 Apr 2007) | 1 line QPID-446 Removed hashing of presented password in Base64MD5PasswordFilePrincipalDatabase. ........ r527876 | rgodfrey | 2007-04-12 11:31:51 +0100 (Thu, 12 Apr 2007) | 3 lines QPID-451 Throw InvalidDestinationException on attempt to publish to a Queue which does not exist Changed QueueSenderAdapter to check if the routing key is bound to a queue on the given exchange. The checking can be turned off by setting the system property org.apache.qpid.client.verifyQueueBindingBeforePublish to anything but true ........ r527941 | bhupendrab | 2007-04-12 14:49:10 +0100 (Thu, 12 Apr 2007) | 1 line not needed for management console ........ r527959 | bhupendrab | 2007-04-12 15:40:36 +0100 (Thu, 12 Apr 2007) | 1 line refining the mbean operations ........ r527972 | ritchiem | 2007-04-12 16:11:16 +0100 (Thu, 12 Apr 2007) | 3 lines QPID-446 Updated sample configs to contain jmx security options. ........ r528003 | marnie | 2007-04-12 17:15:48 +0100 (Thu, 12 Apr 2007) | 1 line QPID-352 Changes ........ r528005 | marnie | 2007-04-12 17:16:34 +0100 (Thu, 12 Apr 2007) | 1 line QPID-352 Changes ........ r528424 | rgreig | 2007-04-13 11:17:12 +0100 (Fri, 13 Apr 2007) | 1 line Created new ping client that sends messages only. Usefull for examaning known queue states in mgmnt console. ........ r529233 | bhupendrab | 2007-04-16 14:25:58 +0100 (Mon, 16 Apr 2007) | 1 line added parameter for SASL ........ r529246 | bhupendrab | 2007-04-16 14:48:31 +0100 (Mon, 16 Apr 2007) | 1 line removed default username as guest. Added hashing for new user password field. ........ r529297 | rgodfrey | 2007-04-16 16:53:45 +0100 (Mon, 16 Apr 2007) | 1 line QPID-453 : AMQShortString should implement Comparable ........ r529635 | bhupendrab | 2007-04-17 16:07:06 +0100 (Tue, 17 Apr 2007) | 1 line QPID-422 : Combined all user configured notifications on one view. ........ r529659 | ritchiem | 2007-04-17 17:08:00 +0100 (Tue, 17 Apr 2007) | 7 lines QPID-454 Message 'taken' notion is per message. But should be per message per queue AMQChannel - pass queue in on all take/release/getSubscriptionDelievered calls BasicRejectMethodHandler - pass queue in on getSubscriptionDelievered calls AMQMessage - Changes to require AMQQueue on all take/release/getSubscriptionDelievered calls ConcurrentSelectorDeliveryManager - pass queue in on take/release/getSubscriptionDelievered calls SubscriptionImpl - - pass queue in on release calls ........ r529666 | ritchiem | 2007-04-17 17:19:59 +0100 (Tue, 17 Apr 2007) | 11 lines QPID-455 Prefetched messages can cause problems with client tools. AMQSession - suspend channel at startup until start() and recieve/setMessageListener are called. BasicMessageConsumer - mainly style sheet changes MessageListenerMultiConsumerTest - removed one test case as we cannot ensure round-robin effect at start up .. added test case for only c2 consuming when c1 does nothing. MessageListenerTest - added new test that can demonstrate a further bug of message 'loss' when a receive is called only once before a message listener is set. Prefetched message end up on _SynchronousQueue regression of QPID-293 as of r501004. MessageRequeueTest - Was missing a conn.start() DurableSubscriptionTest - Removed blocking receives() so we don't block on failure CommitRollbackTest - Text message was wrong on testGetThenDisconnect tests so adjusted ........ r529669 | bhupendrab | 2007-04-17 17:43:53 +0100 (Tue, 17 Apr 2007) | 1 line QPID-417 ........ r530034 | bhupendrab | 2007-04-18 15:32:02 +0100 (Wed, 18 Apr 2007) | 2 lines AMQUserManagementMBean.java - calling relaod within viewUsers method. Creating user list on management console instead of typing the user name. ........ r530037 | ritchiem | 2007-04-18 15:37:30 +0100 (Wed, 18 Apr 2007) | 1 line QPID-454 Message 'taken' notion is per message. REVERTED as it just wasn't right.. needs to be refactored. ........ r530041 | ritchiem | 2007-04-18 15:40:47 +0100 (Wed, 18 Apr 2007) | 1 line QPID-457 Fixed rollback inTran problem with test case ........ r530042 | ritchiem | 2007-04-18 15:42:16 +0100 (Wed, 18 Apr 2007) | 1 line QPID-457 Fixed rollback inTran problem with test case Missed the actual file fix. ........ r530043 | ritchiem | 2007-04-18 15:46:36 +0100 (Wed, 18 Apr 2007) | 1 line QPID-458 Fix to make the CSDM check if a message is taken when deliverying to browser. Removing the message from the queue and continuing if that is the caee. ........ r530044 | ritchiem | 2007-04-18 15:54:36 +0100 (Wed, 18 Apr 2007) | 1 line Removed e.printstacktrace that sneaked in with the other code style changes. ........ r530047 | ritchiem | 2007-04-18 16:09:28 +0100 (Wed, 18 Apr 2007) | 1 line Fix for intermittent CRT expected <1> but was <2> errors ........ r530048 | ritchiem | 2007-04-18 16:10:24 +0100 (Wed, 18 Apr 2007) | 3 lines ResetMessageListenerTest was using the wrong queue for running tests. This was causing problems during testing. Changed queue to use ResetMessageListenerTest queue ........ r530049 | ritchiem | 2007-04-18 16:11:22 +0100 (Wed, 18 Apr 2007) | 2 lines QPID-455 Prefetched messages can cause problems with client tools. Removed the changes as this was causing problems. Guarded with a check for now but solution is till not correct. ........ r530052 | ritchiem | 2007-04-18 16:12:45 +0100 (Wed, 18 Apr 2007) | 1 line QPID-455 - Guarded test with a check until a full solution is found ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@530474 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/message/TestMessageFactory.java | 2 +- .../org/apache/qpid/config/AbstractConfig.java | 4 +- .../config/JBossConnectionFactoryInitialiser.java | 5 +- .../org/apache/qpid/ping/PingDurableClient.java | 40 ++++++++++++++- .../org/apache/qpid/ping/PingSendOnlyClient.java | 57 +++++++++++++++++++++ .../apache/qpid/requestreply/PingPongProducer.java | 59 ++++++++++++---------- .../main/java/org/apache/qpid/topic/Config.java | 2 +- 7 files changed, 134 insertions(+), 35 deletions(-) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java index c0f236b833..eeb4021f34 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java @@ -103,7 +103,7 @@ public class TestMessageFactory { StringBuffer buf = new StringBuffer(size); int count = 0; - while (count < size) + while (count <= (size - MESSAGE_DATA_BYTES.length())) { buf.append(MESSAGE_DATA_BYTES); count += MESSAGE_DATA_BYTES.length(); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java index 04381d66a0..14db74438f 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java @@ -49,7 +49,7 @@ public abstract class AbstractConfig } catch(NumberFormatException e) { - throw new RuntimeException(msg + ": " + i); + throw new RuntimeException(msg + ": " + i, e); } } @@ -61,7 +61,7 @@ public abstract class AbstractConfig } catch(NumberFormatException e) { - throw new RuntimeException(msg + ": " + i); + throw new RuntimeException(msg + ": " + i, e); } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java index 44285efd96..a0248a8f79 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java @@ -22,6 +22,7 @@ package org.apache.qpid.config; import org.apache.qpid.config.ConnectionFactoryInitialiser; import org.apache.qpid.config.ConnectorConfig; +import org.apache.qpid.client.JMSAMQException; import javax.jms.ConnectionFactory; import javax.jms.JMSException; @@ -63,11 +64,11 @@ public class JBossConnectionFactoryInitialiser implements ConnectionFactoryIniti } catch (NamingException e) { - throw new JMSException("Unable to lookup object: " + e); + throw new JMSAMQException("Unable to lookup object: " + e, e); } catch (Exception e) { - throw new JMSException("Error creating topic: " + e); + throw new JMSAMQException("Error creating topic: " + e, e); } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java index 82e43e542f..0e832ef100 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java @@ -1,3 +1,4 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -178,6 +179,7 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList // Run the test procedure. int sent = pingProducer.send(); + pingProducer.closeConnection(); pingProducer.waitForUser("Press return to begin receiving the pings."); pingProducer.receive(sent); @@ -302,6 +304,13 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList System.out.println("Messages sent: " + messagesSent + ", Messages Committed = " + messagesCommitted + ", Messages not Committed = " + messagesNotCommitted); + + + return messagesSent; + } + + protected void closeConnection() + { // Clean up the connection. try { @@ -309,10 +318,11 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList } catch (JMSException e) { + log.debug("There was an error whilst closing the connection: " + e, e); + System.out.println("There was an error whilst closing the connection."); + // Ignore as did best could manage to clean up. } - - return messagesSent; } protected void receive(int messagesSent) throws Exception @@ -354,6 +364,32 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList } } + // Ensure messages received are committed. + if (_transacted) + { + try + { + _consumerSession.commit(); + System.out.println("Committed for all messages received."); + } + catch (JMSException e) + { + log.debug("Error during commit: " + e, e); + System.out.println("Error during commit."); + try + { + _consumerSession.rollback(); + System.out.println("Rolled back on all messages received."); + } + catch (JMSException e2) + { + log.debug("Error during rollback: " + e, e); + System.out.println("Error on roll back of all messages received."); + } + + } + } + log.debug("messagesReceived = " + messagesReceived); System.out.println("Messages received: " + messagesReceived); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java new file mode 100644 index 0000000000..7cf5e4516f --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java @@ -0,0 +1,57 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ +package org.apache.qpid.ping; + +import java.util.Properties; + +import org.apache.log4j.Logger; + +import org.apache.qpid.util.CommandLineParser; + +/** + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    + */ +public class PingSendOnlyClient extends PingDurableClient +{ + private static final Logger log = Logger.getLogger(PingSendOnlyClient.class); + + public PingSendOnlyClient(Properties overrides) throws Exception + { + super(overrides); + } + + /** + * Starts the ping/wait/receive process. + * + * @param args The command line arguments. + */ + public static void main(String[] args) + { + try + { + // Create a ping producer overriding its defaults with all options passed on the command line. + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); + PingDurableClient pingProducer = new PingSendOnlyClient(options); + + // Create a shutdown hook to terminate the ping-pong producer. + Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); + + // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. + // pingProducer.getConnection().setExceptionListener(pingProducer); + + // Run the test procedure. + int sent = pingProducer.send(); + pingProducer.waitForUser("Press return to close connection and quit."); + pingProducer.closeConnection(); + + System.exit(0); + } + catch (Exception e) + { + System.err.println(e.getMessage()); + log.error("Top level handler caught execption.", e); + System.exit(1); + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 913685bca2..ecaf27167f 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -116,7 +116,7 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; * by the PPP that it is atteched to. * * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock pair. - * Obtian read lock on all messages, before decrementing the message count. At the end of the on message method add a + * Obtain read lock on all messages, before decrementing the message count. At the end of the on message method add a * block that obtains the write lock for the very last message, releases any waiting producer. Means that the last * message waits until all other messages have been handled before releasing producers but allows messages to be * processed concurrently, unlike the current synchronized block. @@ -725,6 +725,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis log.debug("public void createReplyConsumers(Collection destinations = " + destinations + ", String selector = " + selector + "): called"); + log.debug("Creating " + destinations.size() + " reply consumers."); + for (Destination destination : destinations) { // Create a consumer for the destination and set this pinger to listen to its messages. @@ -732,6 +734,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _consumerSession.createConsumer(destination, PREFETCH_DEFAULT, NO_LOCAL_DEFAULT, EXCLUSIVE_DEFAULT, selector); _consumer.setMessageListener(this); + + log.debug("Set this to listen to replies sent to destination: " + destination); } } @@ -743,13 +747,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public void onMessage(Message message) { - log.debug("public void onMessage(Message message): called"); + // log.debug("public void onMessage(Message message): called"); try { // Extract the messages correlation id. String correlationID = message.getJMSCorrelationID(); - log.debug("correlationID = " + correlationID); + // log.debug("correlationID = " + correlationID); // Countdown on the traffic light if there is one for the matching correlation id. PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); @@ -761,7 +765,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Restart the timeout timer on every message. perCorrelationId.timeOutStart = System.nanoTime(); - log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); + // log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); // Decrement the countdown latch. Before this point, it is possible that two threads might enter this // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block @@ -776,8 +780,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis trueCount = trafficLight.getCount(); remainingCount = trueCount - 1; - log.debug("remainingCount = " + remainingCount); - log.debug("trueCount = " + trueCount); + // log.debug("remainingCount = " + remainingCount); + // log.debug("trueCount = " + trueCount); // Commit on transaction batch size boundaries. At this point in time the waiting producer remains // blocked, even on the last message. @@ -806,23 +810,23 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } // Print out ping times for every message in verbose mode only. - if (_verbose) + /*if (_verbose) { Long timestamp = message.getLongProperty(MESSAGE_TIMESTAMP_PROPNAME); if (timestamp != null) { long diff = System.nanoTime() - timestamp; - log.trace("Time for round trip (nanos): " + diff); + //log.trace("Time for round trip (nanos): " + diff); } - } + }*/ } catch (JMSException e) { log.warn("There was a JMSException: " + e.getMessage(), e); } - log.debug("public void onMessage(Message message): ending"); + // log.debug("public void onMessage(Message message): ending"); } /** @@ -955,16 +959,16 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis committed = false; // Re-timestamp the message. - message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); + // message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); // Send the message, passing in the message count. committed = sendMessage(i, message); // Spew out per message timings on every message sonly in verbose mode. - if (_verbose) + /*if (_verbose) { log.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); - } + }*/ } // Call commit if the send loop finished before reaching a batch size boundary so there may still be uncommitted messages. @@ -1003,7 +1007,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _failBeforeSend = false; } - log.trace("Failing Before Send"); + // log.trace("Failing Before Send"); waitForUser(KILL_BROKER_PROMPT); } @@ -1176,6 +1180,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis if (_connection != null) { _connection.close(); + log.debug("Close connection."); } } finally @@ -1213,20 +1218,20 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ protected boolean commitTx(Session session) throws JMSException { - log.debug("protected void commitTx(Session session): called"); + // log.debug("protected void commitTx(Session session): called"); boolean committed = false; - log.trace("Batch time reached"); + // log.trace("Batch time reached"); if (_failAfterSend) { - log.trace("Batch size reached"); + // log.trace("Batch size reached"); if (_failOnce) { _failAfterSend = false; } - log.trace("Failing After Send"); + // log.trace("Failing After Send"); waitForUser(KILL_BROKER_PROMPT); } @@ -1241,14 +1246,14 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _failBeforeCommit = false; } - log.trace("Failing Before Commit"); + // log.trace("Failing Before Commit"); waitForUser(KILL_BROKER_PROMPT); } - long l = System.nanoTime(); + // long l = System.nanoTime(); session.commit(); committed = true; - log.debug("Time taken to commit :" + ((System.nanoTime() - l) / 1000000f) + " ms"); + // log.debug("Time taken to commit :" + ((System.nanoTime() - l) / 1000000f) + " ms"); if (_failAfterCommit) { @@ -1257,15 +1262,15 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _failAfterCommit = false; } - log.trace("Failing After Commit"); + // log.trace("Failing After Commit"); waitForUser(KILL_BROKER_PROMPT); } - log.trace("Session Commited."); + // log.trace("Session Commited."); } catch (JMSException e) { - log.trace("JMSException on commit:" + e.getMessage(), e); + log.debug("JMSException on commit:" + e.getMessage(), e); // Warn that the bounce back client is not available. if (e.getLinkedException() instanceof AMQNoConsumersException) @@ -1276,11 +1281,11 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis try { session.rollback(); - log.trace("Message rolled back."); + log.debug("Message rolled back."); } catch (JMSException jmse) { - log.trace("JMSE on rollback:" + jmse.getMessage(), jmse); + log.debug("JMSE on rollback:" + jmse.getMessage(), jmse); // Both commit and rollback failed. Throw the rollback exception. throw jmse; @@ -1296,7 +1301,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * * @param prompt The prompt to display on the console. */ - protected void waitForUser(String prompt) + public void waitForUser(String prompt) { System.out.println(prompt); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java index 342b28ca17..d5c0979399 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java @@ -221,7 +221,7 @@ public class Config extends AbstractConfig implements ConnectorConfig } catch(NumberFormatException e) { - throw new RuntimeException("Bad port number: " + value); + throw new RuntimeException("Bad port number: " + value, e); } } else if("-payload".equalsIgnoreCase(key)) -- cgit v1.2.1 From 977abc4f3ee3a4b9d34a325c9cfb6ea15bc5bf4e Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 26 Apr 2007 15:28:48 +0000 Subject: Merged revisions 1-447993,447995-448007,448009-448141,448143-448157,448161-448194,448196-448210,448212-448218,448220-448223,448225-448233,448235,448237-448241,448243-448596,448598-448623,448625-448850,448852-448880,448882-448982,448984-449635,449637-449639,449641-449642,449644-449645,449647-449674,449676-449719,449721-449749,449751-449762,449764-449933,449935-449941,449943-450383,450385,450387-450400,450402-450433,450435-450503,450505-450555,450557-450860,450862-451024,451026-451149,451151-451316,451318-451931,451933-452139,452141-452162,452164-452320,452322,452324-452325,452327-452333,452335-452429,452431-452528,452530-452545,452547-453192,453194-453195,453197-453536,453538,453540-453656,453658-454676,454678-454735,454737,454739-454781,454783-462728,462730-462819,462821-462833,462835-462839,462841-463071,463073-463178,463180-463308,463310-463362,463364-463375,463377-463396,463398-463402,463404-463409,463411-463661,463663-463670,463672-463673,463675-464493,464495-464502,464504-464576,464578-464613,464615-464628,464630,464632-464866,464868-464899,464901-464942,464944-464949,464951-465004,465006-465016,465018-465053,465055-465165,465167-465321,465323-465406,465408-465427,465429-465431,465433-465548,465550-466044,466047-466075,466077,466079-466081,466083-466099,466101-466112,466114-466126,466128-466240,466242-466971,466973-466978,466980-467309,467311-467312,467316-467328,467330-467485,467487-467588,467590-467604,467606-467699,467701-467706,467708-467749,467751-468069,468071-468537,468539-469241,469244-469246,469248-469318,469320-469421,469423,469425-469429,469431-469435,469437-469462,469464-469469,469472-469477,469479-469490,469492-469503,469505-469529,469531-469598,469600-469624,469626-469737,469739-469752,469754-469806,469808-469928,469930-469953,469955-470011,470013-470109,470111-470335,470338-470339,470341-470379,470381,470383-470399,470401-470446,470448-470741,470743-470758,470760-470809,470811-470817,470819-470993,470995-471001,471003-471788,471790-471792,471794-472028,472030-472032,472034-472036,472038,472040,472043,472045-472059,472061,472063,472065-472066,472068,472070-472072,472074-472080,472082,472084-472092,472094-472107,472109-472123,472125-472158,472160-472165,472167-472172,472174-472457,472459-472460,472462-472464,472466-472470,472472-472483,472486-472491,472493-472494,472496-472497,472499,472501-472503,472505-472512,472514-472544,472546-472556,472558-472560,472562-472572,472574-472587,472589-472591,472593-472605,472607,472609-472731,472733-472786,472788-472843,472845-472849,472851-472859,472861-472878,472880-472903,472905,472907-472988,472990-472991,472993-473071,473073-473086,473088-473090,473093,473095-473096,473098-473106,473108-473110,473112-473185,473187-473260,473262,473268-473270,473275-473279,473281,473284-473287,473289-473295,473297-473306,473308-473330,473332-473335,473337,473339-473344,473346-473351,473353-473355,473357-473358,473361-473471,473473-473497,473499-473535,473537-473567,473569-473888,473890-474451,474454-474492,474494-474563,474565-474843,474845-474865,474867-474932,474934-475035,475037-475144,475146-475180,475182-475265,475267-475285,475287,475289-475293,475295-475296,475298-475302,475304-475631,475633-475649,475651-475748,475750-475752,475754-476107,476109-476302,476304-476413,476415-476430,476432-476700,476702-476868,476870-477147,477149-477213,477215-477263,477265-477340,477342-477635,477637-477789,477791-477825,477827-477841,477843,477846-477852,477854,477856,477858-477865,477867-477894,477896-478022,478024-478182,478184-478211,478213-478233,478235-478236,478238-478241,478243-478252,478254-478259,478261-478263,478265,478267-478269,478271-478286,478288-478342,478344-478379,478381-478412,478414-478443,478445-478636,478639-478658,478660-478821,478823-478853,478855-478922,478924-478962,478965-478974,478976-479029,479031-479049,479051-479210,479212-479214,479216-479407,479409-479415,479417-479425,479427-479559,479561-479639,479641-479676,479678-479685,479687-480030,480033-480086,480091-480093,480095-480118,480120-480139,480141,480143-480148,480150-480156,480158-480163,480165-480177,480179-480189,480191-480193,480195-480198,480200-480220,480222-480282,480284-480292,480294-480308,480310-480317,480320-480422,480424,480426-480581,480583-480656,480658-480692,480695-480702,480704,480706-480710,480712-480910,480913-480933,480935-480945,480947-480972,480974-480993,480995-481034,481036-481158,481161-481174,481176-481220,481222-481234,481236-481260,481263-481264,481266-481296,481298-481304,481306-481311,481313-481332,481334,481336-481380,481382-481441,481443-482144,482146-482180,482182-482193,482195-482232,482234-482236,482239,482241-482242,482244-482247,482250-482251,482253,482256-482261,482264-482288,482290-482364,482366,482368,482370-482554,482556,482558-482569,482572-482636,482638,482640-482696,482698-482722,482724-482732,482734-482771,482774-482957,482959-483045,483047-483105,483108,483110-483115,483117,483119-483127,483130-483134,483136-483148,483150-483158,483160-483164,483166-483178,483180-483391,483393-483400,483402-483403,483405-483418,483420-483421,483425-483436,483438-483470,483472-483502,483504-483558,483560-483599,483601-483637,483639-483644,483646-483659,483661-483670,483672-483878,483880-483910,483912-483915,483917-483940,483942,483944-483968,483970-483972,483974-483976,483978,483980-484612,484614-484657,484659-484693,484695-484718,484720-484842,484844-484847,484849-484986,484988-485019,485021-485489,485491-485544,485546-485591,485593,485595-485697,485699-485729,485731-485734,485736-485779,485781-485787,485789-485851,485853,485855-486007,486009,486011-486020,486022-486083,486085-486097,486099-486117,486120-486131,486133-486148,486150-486161,486163-486164,486166-486197,486199-486205,486208-486247,486249-486253,486256-486427,486429-486431,486433-486554,486556-486573,486575-486593,486595,486597-486609,486611-486619,486622,486625,486627-486641,486643-486645,486649-486687,486689-486721,486723-486730,486732-486746,486748-486759,486761,486763-486777,486779-486782,486784-486788,486790,486792,486794-486796,486798-487175,487178,487180-487213,487215,487217-487267,487269-487284,487286-487298,487300-487358,487360-487367,487369-487382,487384-487434,487436-487480,487482-487547,487549-487561,487563-487565,487567-487578,487580-487615,487617-487622,487624,487626,487628,487630-487635,487637-487703,487705-487777,487780-487781,487783-487800,487802-487803,487805-487820,487822-487848,487850-487902,487904-488103,488105-488133,488135-488158,488160-488163,488165-488187,488189-488216,488218-488248,488250-488278,488280,488282-488303,488305-488313,488315-488342,488344-488351,488353-488376,488378-488449,488451-488593,488595,488597-488623,488625-488700,488702-488704,488706-488710,488714,488716-488725,488727-488744,488746-488770,488772-488798,488800,488802-488807,488809,488811-488829,488831-488843,488845-488851,488853-489069,489071-489077,489079-489081,489084-489102,489104-489105,489107-489109,489111-489112,489114-489139,489141-489178,489181-489203,489205-489211,489213,489216-489329,489332-489402,489404-489417,489419-489421,489423-489643,489645-489690,489692-489703,489705-489714,489716-489747,489749-489753,489755-489803,489805-489904,489906-490372,490374-490504,490506-490604,490606-490707,490710-490733,490735-490871,490873-490984,490986-491028,491030,491032-491071,491073-491119,491121-491576,491578-491672,491674-491800,491802-491838,491840-491878,491880-492183,492185-492279,492281-492317,492319-492513,492515-492584,492586-492587,492589-492601,492603-492635,492637-492640,492642-492717,492719-492723,492725-492729,492731-492755,492757-492901,492903-492955,492957-492962,492964-492997,492999-493002,493004-493041,493043-493059,493062-493063,493065-493086,493088-493125,493127-493139,493141-493150,493152-493871,493873-494017,494019-494030,494032-494041,494043-494091,494093-494120,494122-494354,494356-494436,494438-494539,494541-494552,494554-494586,494588-494649,494651,494653-494654,494656-494657,494659-494764,494766-494768,494770-494796,494798-494799,494802,494804-494860,494862-494903,494905-494906,494908-495019,495021-495160,495162-495168,495171-495188,495190-495229,495231-495254,495256-495303,495305-495313,495315-495336,495338-495372,495374-495379,495381-495454,495457-495459,495462-495516,495518-495524,495526-495531,495533-495548,495551-495553,495555,495557-495558,495560,495562-495573,495575-495583,495585-495594,495596-495628,495630-495638,495640-495651,495653-495660,495662-495753,495755-496259,496261-496262,496264-496269,496271-496275,496277-496301,496303-496316,496318-496383,496385-496413,496415-496495,496497-496625,496627-496636,496638-496640,496642-496647,496650-496657,496659-496660,496663-496664,496666-496677,496679-496681,496683-496730,496732-496750,496752,496754-496784,496786-496832,496834-496840,496842-496990,496992-496995,496997-497340,497343-497351,497353-497403,497405-497424,497426-497438,497440-497481,497483-497497,497499-497765,497767-497769,497771-497775,497777-497778,497780,497782-497783,497785,497787-497812,497814-497871,497873-497877,497879-498573,498575-498588,498590,498592,498594-498636,498638-498669,498671-498686,498688-498689,498691-498719,498721-498964,498966-498969,498971-498973,498975-498982,498985-499035,499037-499040,499042,499044-499048,499050-499082,499084-499086,499088-499164,499167-499169,499171-499355,499357-499370,499372-499373,499375-499391,499393,499395-499425,499428,499430-499445,499447-499455,499457-499460,499462-499465,499467,499469-499489,499491-499492,499494-499531,499533-499562,499566-499627,499629-499715,499717-499732,499734-499755,499758-499763,499765-499780,499782-499795,499797-499802,499804-499844,499846,499848-499850,499852-499863,499865-499873,499875-499974,499976-499978,499980-500263,500265-500283,500285-500309,500311-501000,501002,501012-501057,501059-501095,501097-501390,501392-501410,501413-501447,501449-501454,501456,501458-501464,501466-501471,501473-501803,501805-501913,501915-501916,501918-501919,501921-501944,501946-502171,502173-502177,502181,502183-502247,502250-502252,502254-502260,502262-502267,502270,502272,502274-502575,502577-502609,502611-502619,502621-502626,502628-502654,502656-503592,503594-503603,503605-503608,503610-503636,503638-503645,503647-503705,503707-503789,503791-504024,504026-504111,504113-504506,504508-504735,504737-504863,504865-504867,504869-504914,504916-505241,505243-505254,505257-505267,505269-505354,505356-505891,505893-505971,505973-506400,506402-506404,506407-506438,506440-506516,506518-506541,506543-506966,506968-506971,506973-507095,507097-507108,507111-507454,507456,507459-507471,507473-507556,507558,507560-507581,507585-507594,507597,507599-507608,507610-507728,507730-507893,507895-507937,507940-508234,508236-508350,508352-508365,508367-508380,508383,508386-508415,508417-508648,508650-508941,508943-509146,509148-509171,509173-509175,509179-509201,509203-509207,509209-509215,509217-509222,509224-509477,509480-509627,509629-509634,509636-509641,509643-509736,509738-509931,509933-510059,510061-510075,510077-510158,510161-510896,510898-510938,510940-511388,511390-511922,511924-512287,512289-512698,512702-512813,512815-512817,512819-513359,513361-513370,513372-514702,514704-514886,514888-514902,514904-515126,515129-515141,515143-515516,515518-515534,515536-515538,515540-515648,515650-515651,515653-516070,516072-516411,516413-516448,516450,516452-517637,517639-517647,517649-517659,517661-517663,517665-517677,517679-517682,517684-517744,517746-518085,518087-518175,518177-518558,518560-518568,518571-518666,518668,518670-518699,518701-518987,518990-518992,518994-519908,519910-519932,519934-520414,520416-520842,520844-520937,520939-521362,521364-521681,521683-521704,521706-521709,521711-521714,521716-521781,521783-521792,521794-522462,522464-522527,522529-522534,522536-522566,522568-522958,522960,522962-522966,522968-522976,522978-522980,522982-522988,522992-522993,522995-523244,523246-523746,523748-524049,524051-524738,524741-524742,524744-524762,524764,524766,524768-525486,525488-525530,525532,525534,525537-525552,525554-525765,525767-525776,525778-525784,525789-525803,525805-525816,525818-525828,525830-525861,525863-525866,525868-526090,526092-526112,526114-526116,526119-526121,526123-526149,526151-526153,526155-526156,526160-526165,526167-526186,526188-526193,526196-526197,526200-526665,526667-526682,526686-526690,526693,526695-526708,526710-526713,526715-526775,526777-526802,526804-526806,526808-527048,527051-527052,527054-527181,527183-527486,527488-527492,527494-527498,527500-527508,527510-527517,527519-527536,527538-527555,527559-527802,527804-527842,527844-527847,527849-527875,527877-527940,527942-527958,527960-527971,527973-528002,528004,528006-528423,528425-529232,529234-529245,529247-529296,529298-529634,529636-529658,529660-529665,529667-529668,529670-530033,530035-530036,530038-530040,530045-530046,530050-530051,530053-530431,530433-530436,530439-530440,530443,530445-530446,530448,530450-530682,530684,530687-530696,530698-530733,530735-530776,530778-530795,530799,530801-530811,530813-530818,530820-530837,530839-531436,531438-531455,531457,531459-531511,531514,531516,531519-531523,531525,531528-532465,532467-532764 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r531859 | ritchiem | 2007-04-24 11:06:41 +0100 (Tue, 24 Apr 2007) | 1 line Defaulted the use of JMX SASL security to false. As this requries the jmxremote.jar from sun which is not Apache license friendly. ........ r531865 | ritchiem | 2007-04-24 11:24:51 +0100 (Tue, 24 Apr 2007) | 1 line Defaulted the use of management.security-enabled security to false. As this requires the jmxremote.jar from sun which is not Apache license friendly. ........ r531908 | bhupendrab | 2007-04-24 13:38:18 +0100 (Tue, 24 Apr 2007) | 1 line Management Console sasl changes ........ r531917 | bhupendrab | 2007-04-24 14:03:55 +0100 (Tue, 24 Apr 2007) | 1 line Added display of build and release versions in Help->About ........ r531937 | ritchiem | 2007-04-24 14:42:03 +0100 (Tue, 24 Apr 2007) | 1 line Reduced logging on requeue. ........ r531989 | bhupendrab | 2007-04-24 16:49:03 +0100 (Tue, 24 Apr 2007) | 1 line Added connection exception handling and refactored the action classes ........ r532002 | bhupendrab | 2007-04-24 17:35:43 +0100 (Tue, 24 Apr 2007) | 1 line Management Console SASL changes ........ r532372 | bhupendrab | 2007-04-25 15:46:03 +0100 (Wed, 25 Apr 2007) | 1 line Made the return type of getTestMessage() to a generic type for subclass to override. ........ r532728 | ritchiem | 2007-04-26 13:38:41 +0100 (Thu, 26 Apr 2007) | 3 lines QPID-292 - Authentication not handled correctly. Copied handling from SecureOkMethod handler. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@532779 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/ping/PingSendOnlyClient.java | 18 +++++++++++++++++- .../org/apache/qpid/requestreply/PingPongProducer.java | 4 ++-- 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java index 7cf5e4516f..29757a20ba 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java @@ -6,6 +6,12 @@ import java.util.Properties; import org.apache.log4j.Logger; import org.apache.qpid.util.CommandLineParser; +import org.apache.qpid.client.message.TestMessageFactory; + +import javax.jms.ObjectMessage; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; /** *

    @@ -32,7 +38,7 @@ public class PingSendOnlyClient extends PingDurableClient { // Create a ping producer overriding its defaults with all options passed on the command line. Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); - PingDurableClient pingProducer = new PingSendOnlyClient(options); + PingSendOnlyClient pingProducer = new PingSendOnlyClient(options); // Create a shutdown hook to terminate the ping-pong producer. Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); @@ -54,4 +60,14 @@ public class PingSendOnlyClient extends PingDurableClient System.exit(1); } } + + public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException + { + Message msg = TestMessageFactory.newTextMessage(_producerSession, messageSize); + + // Timestamp the message in nanoseconds. + msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); + + return msg; + } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index ecaf27167f..5dec2125ee 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -1049,7 +1049,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis try { // Generate a sample message and time stamp it. - ObjectMessage msg = getTestMessage(_replyDestination, _messageSize, _persistent); + Message msg = getTestMessage(_replyDestination, _messageSize, _persistent); msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); // Send the message and wait for a reply. @@ -1096,7 +1096,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. */ - public ObjectMessage getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException + public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException { ObjectMessage msg = TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); -- cgit v1.2.1 From 3f3a7f6af8d3ceb4b48fdea7605a57b5f7bff2ee Mon Sep 17 00:00:00 2001 From: Robert Greig Date: Wed, 2 May 2007 16:47:36 +0000 Subject: Removed accidentally included copyright and author tags. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@534539 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/ping/PingDurableClient.java | 3 --- .../main/java/org/apache/qpid/ping/PingSendOnlyClient.java | 13 ++++++------- 2 files changed, 6 insertions(+), 10 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java index 0e832ef100..2765986868 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java @@ -1,4 +1,3 @@ -/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -304,8 +303,6 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList System.out.println("Messages sent: " + messagesSent + ", Messages Committed = " + messagesCommitted + ", Messages not Committed = " + messagesNotCommitted); - - return messagesSent; } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java index 29757a20ba..ed0ac49ef9 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java @@ -1,17 +1,16 @@ -/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ package org.apache.qpid.ping; import java.util.Properties; -import org.apache.log4j.Logger; - -import org.apache.qpid.util.CommandLineParser; -import org.apache.qpid.client.message.TestMessageFactory; - -import javax.jms.ObjectMessage; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; +import javax.jms.ObjectMessage; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.util.CommandLineParser; /** *

    CRC Card
    -- cgit v1.2.1 From 1d6bec9c7ea9f4ea71a919e59010fd0744581ac9 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 7 May 2007 09:40:58 +0000 Subject: Merged revisions 534897-534902,534904-535253,535255-535809 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r534897 | bhupendrab | 2007-05-03 15:53:20 +0100 (Thu, 03 May 2007) | 1 line Attribute details background made same as other displays. ........ r535309 | ritchiem | 2007-05-04 17:12:59 +0100 (Fri, 04 May 2007) | 2 lines QPID-466 Changes to FieldTable along with corresponding PropertyValueTest to limit the Java client to only AMQP 0-8 compliant values. ........ r535809 | ritchiem | 2007-05-07 10:28:15 +0100 (Mon, 07 May 2007) | 5 lines QPID-466 Updated FieldTable to ensure no Decimal value is set that is larger than can be transmitted over AMQP. That is a max scale value of Byte.MAX_VALUE and value of up to Integer.MAX_VALUE. Additional tests to ensure this is the case. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@535819 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongProducer.java | 182 ++++++++++++--------- 1 file changed, 105 insertions(+), 77 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 5dec2125ee..642f3077fd 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -37,6 +37,7 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.client.*; import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.client.message.AMQMessage; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.jms.MessageProducer; @@ -374,7 +375,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * ping producers on the same JVM. */ private static Map perCorrelationIds = - Collections.synchronizedMap(new HashMap()); + Collections.synchronizedMap(new HashMap()); /** A convenient formatter to use when time stamping output. */ protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); @@ -549,13 +550,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * Starts a ping-pong loop running from the command line. The bounce back client {@link PingPongBouncer} also needs * to be started to bounce the pings back again. * - * @param args The command line arguments. + * @param args The command line arguments. */ public static void main(String[] args) { try { - Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][]{})); // Create a ping producer overriding its defaults with all options passed on the command line. PingPongProducer pingProducer = new PingPongProducer(options); @@ -597,7 +598,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis Thread.sleep(sleepTime); } catch (InterruptedException ie) - { } + { + } } } @@ -648,11 +650,11 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * @throws JMSException Any JMSExceptions are allowed to fall through. */ public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique, - boolean durable) throws JMSException, AMQException + boolean durable) throws JMSException, AMQException { log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " - + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = " - + durable + "): called"); + + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = " + + durable + "): called"); _pingDestinations = new ArrayList(); @@ -688,8 +690,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis else { destination = - AMQTopic.createDurableTopic(new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id), - _clientID, (AMQConnection) _connection); + AMQTopic.createDurableTopic(new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id), + _clientID, (AMQConnection) _connection); log.debug("Created durable topic " + destination); } } @@ -698,11 +700,11 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { AMQShortString destinationName = new AMQShortString(rootName + id); destination = - new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, destinationName, destinationName, false, false, - _isDurable); + new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, destinationName, destinationName, false, false, + _isDurable); ((AMQSession) _producerSession).createQueue(destinationName, false, _isDurable, false); ((AMQSession) _producerSession).bindQueue(destinationName, destinationName, null, - ExchangeDefaults.DIRECT_EXCHANGE_NAME); + ExchangeDefaults.DIRECT_EXCHANGE_NAME); log.debug("Created queue " + destination); } @@ -715,15 +717,15 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** * Creates consumers for the specified destinations and registers this pinger to listen to their messages. * - * @param destinations The destinations to listen to. - * @param selector A selector to filter the messages with. + * @param destinations The destinations to listen to. + * @param selector A selector to filter the messages with. * * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through. */ public void createReplyConsumers(Collection destinations, String selector) throws JMSException { log.debug("public void createReplyConsumers(Collection destinations = " + destinations - + ", String selector = " + selector + "): called"); + + ", String selector = " + selector + "): called"); log.debug("Creating " + destinations.size() + " reply consumers."); @@ -731,8 +733,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { // Create a consumer for the destination and set this pinger to listen to its messages. _consumer = - _consumerSession.createConsumer(destination, PREFETCH_DEFAULT, NO_LOCAL_DEFAULT, EXCLUSIVE_DEFAULT, - selector); + _consumerSession.createConsumer(destination, PREFETCH_DEFAULT, NO_LOCAL_DEFAULT, EXCLUSIVE_DEFAULT, + selector); _consumer.setMessageListener(this); log.debug("Set this to listen to replies sent to destination: " + destination); @@ -740,8 +742,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Stores the received message in the replies map, then resets the boolean latch that a thread waiting for a correlating - * reply may be waiting on. This is only done if the reply has a correlation id that is expected in the replies map. + * Stores the received message in the replies map, then resets the boolean latch that a thread waiting for a + * correlating reply may be waiting on. This is only done if the reply has a correlation id that is expected in the + * replies map. * * @param message The received message. */ @@ -830,26 +833,26 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out before a - * reply arrives, then a null reply is returned from this method. This method allows the caller to specify the - * correlation id. + * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out + * before a reply arrives, then a null reply is returned from this method. This method allows the caller to specify + * the correlation id. * - * @param message The message to send. If this is null, one is generated. - * @param numPings The number of ping messages to send. - * @param timeout The timeout in milliseconds. - * @param messageCorrelationId The message correlation id. If this is null, one is generated. + * @param message The message to send. If this is null, one is generated. + * @param numPings The number of ping messages to send. + * @param timeout The timeout in milliseconds. + * @param messageCorrelationId The message correlation id. If this is null, one is generated. * - * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait for - * all prematurely. + * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait + * for all prematurely. * * @throws JMSException All underlying JMSExceptions are allowed to fall through. * @throws InterruptedException When interrupted by a timeout */ public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) - throws JMSException, InterruptedException + throws JMSException, InterruptedException { log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " - + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called"); + + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called"); // Generate a unique correlation id to put on the messages before sending them, if one was not specified. if (messageCorrelationId == null) @@ -929,16 +932,16 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** * Sends the specified number of ping messages and does not wait for correlating replies. * - * @param message The message to send. - * @param numPings The number of pings to send. - * @param messageCorrelationId A correlation id to place on all messages sent. + * @param message The message to send. + * @param numPings The number of pings to send. + * @param messageCorrelationId A correlation id to place on all messages sent. * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException { log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings - + ", String messageCorrelationId = " + messageCorrelationId + "): called"); + + ", String messageCorrelationId = " + messageCorrelationId + "): called"); if (message == null) { @@ -1040,9 +1043,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Implements a single iteration of the ping loop. This sends the number of pings specified by the transaction - * batch size property, and waits for replies to all of them. Any errors cause the publish flag to be cleared, - * which will terminate the pinger. + * Implements a single iteration of the ping loop. This sends the number of pings specified by the transaction batch + * size property, and waits for replies to all of them. Any errors cause the publish flag to be cleared, which will + * terminate the pinger. */ public void pingLoop() { @@ -1050,7 +1053,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { // Generate a sample message and time stamp it. Message msg = getTestMessage(_replyDestination, _messageSize, _persistent); - msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); + setTimestamp(msg); // Send the message and wait for a reply. pingAndWaitForReply(msg, TX_BATCH_SIZE_DEFAULT, TIMEOUT_DEFAULT, null); @@ -1068,7 +1071,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set here. + * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set + * here. * * @param messageListener The chained message listener. */ @@ -1077,9 +1081,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _chainedMessageListener = messageListener; } - /** - * Removes any chained message listeners from this pinger. - */ + /** Removes any chained message listeners from this pinger. */ public void removeChainedMessageListener() { _chainedMessageListener = null; @@ -1088,9 +1090,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** * Generates a test message of the specified size, with the specified reply-to destination and persistence flag. * - * @param replyQueue The reply-to destination for the message. - * @param messageSize The desired size of the message in bytes. - * @param persistent true if the message should use persistent delivery, false otherwise. + * @param replyQueue The reply-to destination for the message. + * @param messageSize The desired size of the message in bytes. + * @param persistent true if the message should use persistent delivery, false otherwise. * * @return A freshly generated test message. * @@ -1101,23 +1103,50 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis ObjectMessage msg = TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); // Timestamp the message in nanoseconds. - msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); + + setTimestamp(msg); return msg; } + protected void setTimestamp(Message msg) throws JMSException + { + if (((AMQSession) _producerSession).isStrictAMQP()) + { + ((AMQMessage) msg).setTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME), System.nanoTime()); + } + else + { + msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); + } + } + + protected long getTimestamp(Message msg) throws JMSException + { + + if (((AMQSession) _producerSession).isStrictAMQP()) + { + Long value = ((AMQMessage) msg).getTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME)); + + return value == null ? 0L : value; + } + else + { + return msg.getLongProperty(PingPongProducer.MESSAGE_TIMESTAMP_PROPNAME); + } + } + + /** - * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this - * flag has been cleared. + * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this flag + * has been cleared. */ public void stop() { _publish = false; } - /** - * Implements a ping loop that repeatedly pings until the publish flag becomes false. - */ + /** Implements a ping loop that repeatedly pings until the publish flag becomes false. */ public void run() { // Keep running until the publish flag is cleared. @@ -1128,8 +1157,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the connection, - * this clears the publish flag which in turn will halt the ping loop. + * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the + * connection, this clears the publish flag which in turn will halt the ping loop. * * @param e The exception that triggered this callback method. */ @@ -1140,20 +1169,20 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered with - * the runtime system as a shutdown hook. + * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered + * with the runtime system as a shutdown hook. * * @return A shutdown hook for the ping loop. */ public Thread getShutdownHook() { return new Thread(new Runnable() - { - public void run() - { - stop(); - } - }); + { + public void run() + { + stop(); + } + }); } /** @@ -1202,19 +1231,18 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit is * applied. This flag applies whether the pinger is transactional or not. * - *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the commit is - * applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker after the commit - * is applied. These flags will only apply if using a transactional pinger. - * - * @param session The session to commit + *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the commit + * is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker after the + * commit is applied. These flags will only apply if using a transactional pinger. * - * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + * @param session The session to commit * * @return true if the session was committed, false if it was not. * - * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit - * method, because commits only apply to transactional pingers, but fail after send applied to transactional and - * non-transactional alike. + * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit + * method, because commits only apply to transactional pingers, but fail after send applied to transactional and + * non-transactional alike. */ protected boolean commitTx(Session session) throws JMSException { @@ -1335,12 +1363,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** * Defines a chained message listener interface that can be attached to this pinger. Whenever this pinger's {@link * PingPongProducer#onMessage} method is called, the chained listener set through the {@link - * PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected count of messages - * with that correlation id. + * PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected count of + * messages with that correlation id. * - *

    Provided only one pinger is producing messages with that correlation id, the chained listener will always be given - * unique message counts. It will always be called while the producer waiting for all messages to arrive is still - * blocked. + *

    Provided only one pinger is producing messages with that correlation id, the chained listener will always be + * given unique message counts. It will always be called while the producer waiting for all messages to arrive is + * still blocked. */ public static interface ChainedMessageListener { @@ -1348,8 +1376,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Holds information on each correlation id. The countdown latch, the current timeout timer... More stuff to be added to - * this: read/write lock to make onMessage more concurrent as described in class header comment. + * Holds information on each correlation id. The countdown latch, the current timeout timer... More stuff to be + * added to this: read/write lock to make onMessage more concurrent as described in class header comment. */ protected static class PerCorrelationId { -- cgit v1.2.1 From d5f768b000a861cb28239a00c7494f49fa1e0446 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 9 May 2007 15:08:56 +0000 Subject: Merged revisions 536141-536162,536165-536243 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r536141 | ritchiem | 2007-05-08 10:54:30 +0100 (Tue, 08 May 2007) | 1 line Added default password file for use with Base64MD5PassswordFilePrincipalDatabase ........ r536243 | rgreig | 2007-05-08 17:31:27 +0100 (Tue, 08 May 2007) | 1 line Some robustness added to tests by limiting buffered messages. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@536559 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongProducer.java | 134 +++++++++++++++------ 1 file changed, 97 insertions(+), 37 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 642f3077fd..1b4fa6b779 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -25,7 +25,9 @@ import java.net.InetAddress; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; +import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -36,8 +38,8 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.client.*; -import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.client.message.AMQMessage; +import org.apache.qpid.client.message.TestMessageFactory; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.jms.MessageProducer; @@ -96,7 +98,10 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; * 3 - DUPS_OK_ACKNOWLEDGE * 257 - NO_ACKNOWLEDGE * 258 - PRE_ACKNOWLEDGE - *

    CRC Card
    pauseBatch 0 In milliseconds. A pause to insert between transaction batches. + *
    maxPending 0 The maximum size in bytes, of messages send but not yet received. + * Limits the volume of messages currently buffered on the client + * or broker. Can help scale test clients by limiting amount of buffered + * data to avoid out of memory errors. *
    * *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop @@ -265,11 +270,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Defines the default message acknowledgement mode. */ public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; - /** Holds the name of the property to get the pause between batches property from. */ - public static final String PAUSE_AFTER_BATCH_PROPNAME = "pauseBatch"; - - /** Defines the default time in milliseconds to wait between commit batches. */ - public static final long PAUSE_AFTER_BATCH_DEFAULT = 0L; + public static final String MAX_PENDING_PROPNAME = "maxPending"; + public static final int MAX_PENDING_DEFAULT = 0; /** Defines the default prefetch size to use when consuming messages. */ public static final int PREFETCH_DEFAULT = 100; @@ -310,8 +312,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT); defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT); defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT); - defaults.setPropertyIfNull(PAUSE_AFTER_BATCH_PROPNAME, PAUSE_AFTER_BATCH_DEFAULT); defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT); + defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT); } protected String _brokerDetails; @@ -364,8 +366,20 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis protected int _noOfDestinations; protected int _rate; - /** Holds the wait time to insert between every batch of messages committed. */ - private long _pauseBatch; + /** + * Holds the size of the maximum amount of pending data that the client should buffer, sending is suspended + * if this limit is breached. + */ + protected int _maxPendingSize; + + /** + * Holds a cyclic barrier which is used to synchronize sender and receiver threads, where the sender has elected + * to wait until the number of unreceived message is reduced before continuing to send. + */ + protected CyclicBarrier _sendPauseBarrier = new CyclicBarrier(2); + + /** Keeps a count of the number of message currently sent but not received. */ + protected AtomicInteger _unreceived = new AtomicInteger(0); /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); @@ -375,7 +389,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * ping producers on the same JVM. */ private static Map perCorrelationIds = - Collections.synchronizedMap(new HashMap()); + Collections.synchronizedMap(new HashMap()); /** A convenient formatter to use when time stamping output. */ protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); @@ -472,7 +486,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _isUnique = properties.getPropertyAsBoolean(UNIQUE_DESTS_PROPNAME); _isDurable = properties.getPropertyAsBoolean(DURABLE_DESTS_PROPNAME); _ackMode = properties.getPropertyAsInteger(ACK_MODE_PROPNAME); - _pauseBatch = properties.getPropertyAsLong(PAUSE_AFTER_BATCH_PROPNAME); + _maxPendingSize = properties.getPropertyAsInteger(MAX_PENDING_PROPNAME); // Check that one or more destinations were specified. if (_noOfDestinations < 1) @@ -556,7 +570,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { try { - Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][]{})); + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); // Create a ping producer overriding its defaults with all options passed on the command line. PingPongProducer pingProducer = new PingPongProducer(options); @@ -598,8 +612,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis Thread.sleep(sleepTime); } catch (InterruptedException ie) - { - } + { } } } @@ -650,11 +663,11 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * @throws JMSException Any JMSExceptions are allowed to fall through. */ public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique, - boolean durable) throws JMSException, AMQException + boolean durable) throws JMSException, AMQException { log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " - + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = " - + durable + "): called"); + + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = " + + durable + "): called"); _pingDestinations = new ArrayList(); @@ -690,8 +703,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis else { destination = - AMQTopic.createDurableTopic(new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id), - _clientID, (AMQConnection) _connection); + AMQTopic.createDurableTopic(new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id), + _clientID, (AMQConnection) _connection); log.debug("Created durable topic " + destination); } } @@ -700,11 +713,11 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { AMQShortString destinationName = new AMQShortString(rootName + id); destination = - new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, destinationName, destinationName, false, false, - _isDurable); + new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, destinationName, destinationName, false, false, + _isDurable); ((AMQSession) _producerSession).createQueue(destinationName, false, _isDurable, false); ((AMQSession) _producerSession).bindQueue(destinationName, destinationName, null, - ExchangeDefaults.DIRECT_EXCHANGE_NAME); + ExchangeDefaults.DIRECT_EXCHANGE_NAME); log.debug("Created queue " + destination); } @@ -725,7 +738,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public void createReplyConsumers(Collection destinations, String selector) throws JMSException { log.debug("public void createReplyConsumers(Collection destinations = " + destinations - + ", String selector = " + selector + "): called"); + + ", String selector = " + selector + "): called"); log.debug("Creating " + destinations.size() + " reply consumers."); @@ -733,8 +746,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { // Create a consumer for the destination and set this pinger to listen to its messages. _consumer = - _consumerSession.createConsumer(destination, PREFETCH_DEFAULT, NO_LOCAL_DEFAULT, EXCLUSIVE_DEFAULT, - selector); + _consumerSession.createConsumer(destination, PREFETCH_DEFAULT, NO_LOCAL_DEFAULT, EXCLUSIVE_DEFAULT, + selector); _consumer.setMessageListener(this); log.debug("Set this to listen to replies sent to destination: " + destination); @@ -783,6 +796,31 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis trueCount = trafficLight.getCount(); remainingCount = trueCount - 1; + // Decrement the count of sent but not yet received messages. + int unreceived = _unreceived.decrementAndGet(); + int unreceivedSize = (unreceived * ((_messageSize == 0) ? 1 : _messageSize)); + + // Release a waiting sender if there is one. + if ((_maxPendingSize > 0) && (unreceivedSize < _maxPendingSize) + && (_sendPauseBarrier.getNumberWaiting() == 1)) + { + log.debug("unreceived size estimate under limit = " + unreceivedSize); + + // Wait on the send pause barrier for the limit to be re-established. + try + { + _sendPauseBarrier.await(); + } + catch (InterruptedException e) + { + throw new RuntimeException(e); + } + catch (BrokenBarrierException e) + { + throw new RuntimeException(e); + } + } + // log.debug("remainingCount = " + remainingCount); // log.debug("trueCount = " + trueCount); @@ -849,10 +887,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * @throws InterruptedException When interrupted by a timeout */ public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) - throws JMSException, InterruptedException + throws JMSException, InterruptedException { log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " - + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called"); + + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called"); // Generate a unique correlation id to put on the messages before sending them, if one was not specified. if (messageCorrelationId == null) @@ -941,7 +979,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException { log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings - + ", String messageCorrelationId = " + messageCorrelationId + "): called"); + + ", String messageCorrelationId = " + messageCorrelationId + "): called"); if (message == null) { @@ -1014,6 +1052,29 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis waitForUser(KILL_BROKER_PROMPT); } + // Increase the count of sent but not yet received messages. + int unreceived = _unreceived.getAndIncrement(); + int unreceivedSize = (unreceived * ((_messageSize == 0) ? 1 : _messageSize)); + + if ((_maxPendingSize > 0) && (unreceivedSize > _maxPendingSize)) + { + log.debug("unreceived size estimate over limit = " + unreceivedSize); + + // Wait on the send pause barrier for the limit to be re-established. + try + { + _sendPauseBarrier.await(); + } + catch (InterruptedException e) + { + throw new RuntimeException(e); + } + catch (BrokenBarrierException e) + { + throw new RuntimeException(e); + } + } + // Send the message either to its round robin destination, or its default destination. if (destination == null) { @@ -1128,7 +1189,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { Long value = ((AMQMessage) msg).getTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME)); - return value == null ? 0L : value; + return (value == null) ? 0L : value; } else { @@ -1136,7 +1197,6 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } } - /** * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this flag * has been cleared. @@ -1177,12 +1237,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public Thread getShutdownHook() { return new Thread(new Runnable() - { - public void run() - { - stop(); - } - }); + { + public void run() + { + stop(); + } + }); } /** -- cgit v1.2.1 From 2b29cdf3d73b64ce1de5a2a1a16228bdcb8376d4 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 9 May 2007 15:20:55 +0000 Subject: Merged revisions 536483-536496 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r536483 | rgreig | 2007-05-09 11:36:06 +0100 (Wed, 09 May 2007) | 1 line Improvements made to max pending message limit code. ........ r536486 | rgreig | 2007-05-09 11:48:39 +0100 (Wed, 09 May 2007) | 1 line Added max buffer limits to all tests. ........ r536496 | rgreig | 2007-05-09 13:11:51 +0100 (Wed, 09 May 2007) | 1 line Improved safety limts for message size tests. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@536564 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongProducer.java | 94 +++++++++++++--------- 1 file changed, 58 insertions(+), 36 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 1b4fa6b779..d5d1c304e9 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -98,7 +98,7 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; * 3 - DUPS_OK_ACKNOWLEDGE * 257 - NO_ACKNOWLEDGE * 258 - PRE_ACKNOWLEDGE - *

    maxPending 0 The maximum size in bytes, of messages send but not yet received. + *
    maxPending 0 The maximum size in bytes, of messages sent but not yet received. * Limits the volume of messages currently buffered on the client * or broker. Can help scale test clients by limiting amount of buffered * data to avoid out of memory errors. @@ -373,10 +373,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis protected int _maxPendingSize; /** - * Holds a cyclic barrier which is used to synchronize sender and receiver threads, where the sender has elected + * Holds a monitor which is used to synchronize sender and receiver threads, where the sender has elected * to wait until the number of unreceived message is reduced before continuing to send. */ - protected CyclicBarrier _sendPauseBarrier = new CyclicBarrier(2); + protected Object _sendPauseMonitor = new Object(); /** Keeps a count of the number of message currently sent but not received. */ protected AtomicInteger _unreceived = new AtomicInteger(0); @@ -801,23 +801,27 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis int unreceivedSize = (unreceived * ((_messageSize == 0) ? 1 : _messageSize)); // Release a waiting sender if there is one. - if ((_maxPendingSize > 0) && (unreceivedSize < _maxPendingSize) - && (_sendPauseBarrier.getNumberWaiting() == 1)) + synchronized (_sendPauseMonitor) { - log.debug("unreceived size estimate under limit = " + unreceivedSize); - - // Wait on the send pause barrier for the limit to be re-established. - try - { - _sendPauseBarrier.await(); - } - catch (InterruptedException e) + if ((_maxPendingSize > 0) && (unreceivedSize < _maxPendingSize)) + // && (_sendPauseBarrier.getNumberWaiting() == 1)) { - throw new RuntimeException(e); - } - catch (BrokenBarrierException e) - { - throw new RuntimeException(e); + log.debug("unreceived size estimate under limit = " + unreceivedSize); + + // Wait on the send pause barrier for the limit to be re-established. + /*try + {*/ + // _sendPauseBarrier.await(); + _sendPauseMonitor.notify(); + /*} + catch (InterruptedException e) + { + throw new RuntimeException(e); + } + catch (BrokenBarrierException e) + { + throw new RuntimeException(e); + }*/ } } @@ -1052,26 +1056,40 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis waitForUser(KILL_BROKER_PROMPT); } - // Increase the count of sent but not yet received messages. - int unreceived = _unreceived.getAndIncrement(); - int unreceivedSize = (unreceived * ((_messageSize == 0) ? 1 : _messageSize)); - - if ((_maxPendingSize > 0) && (unreceivedSize > _maxPendingSize)) + // If necessary, wait until the max pending message size comes within its limit. + synchronized (_sendPauseMonitor) { - log.debug("unreceived size estimate over limit = " + unreceivedSize); - - // Wait on the send pause barrier for the limit to be re-established. - try - { - _sendPauseBarrier.await(); - } - catch (InterruptedException e) + while ((_maxPendingSize > 0)) { - throw new RuntimeException(e); - } - catch (BrokenBarrierException e) - { - throw new RuntimeException(e); + // Get the size estimate of sent but not yet received messages. + int unreceived = _unreceived.get(); + int unreceivedSize = (unreceived * ((_messageSize == 0) ? 1 : _messageSize)); + + if (unreceivedSize > _maxPendingSize) + { + log.debug("unreceived size estimate over limit = " + unreceivedSize); + + // Wait on the send pause barrier for the limit to be re-established. + try + { + // _sendPauseBarrier.await(); + _sendPauseMonitor.wait(1000); + } + catch (InterruptedException e) + { + // Restore the interrupted status + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + /*catch (BrokenBarrierException e) + { + throw new RuntimeException(e); + }*/ + } + else + { + break; + } } } @@ -1085,6 +1103,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _producer.send(destination, message); } + // Increase the unreceived size, this may actually happen aftern the message is recevied. + _unreceived.getAndIncrement(); + // Apply message rate throttling if a rate limit has been set up. if (_rateLimiter != null) { @@ -1300,6 +1321,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * @return true if the session was committed, false if it was not. * * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + * * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit * method, because commits only apply to transactional pingers, but fail after send applied to transactional and * non-transactional alike. -- cgit v1.2.1 From 8c8ee073330c02ba451a7a1a57e7da7110e4d8c0 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 18 Jun 2007 16:29:49 +0000 Subject: Merged revisions 539476-539480,539482-539483,539485-539500,539502-539593,539595-539782,539784-539787,539789-540106,540108-540168,540170-540510,540512-541246,541248-541919,541921-542483,542485-542788,542790-543495,543497-544108,544110-544421,544423-544507,544509-546095,546097-546189,546191-546440,546442-546457,546459-547177,547179-547626,547628-548381 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r539476 | ritchiem | 2007-05-18 15:12:28 +0100 (Fri, 18 May 2007) | 1 line QPID-401 Update to pom to correctly set the broker.dir ........ r544866 | rupertlssmith | 2007-06-06 16:25:02 +0100 (Wed, 06 Jun 2007) | 1 line Updated examples to build source jar. Also put the java14 retrotranslated module back in now that the strange repeating build problem is solved. ........ r545146 | ritchiem | 2007-06-07 12:30:01 +0100 (Thu, 07 Jun 2007) | 1 line POM update renumbering tests now we have trimmed down the tests being run. ........ r548276 | ritchiem | 2007-06-18 10:59:32 +0100 (Mon, 18 Jun 2007) | 1 line Various License header updates. ........ r548279 | ritchiem | 2007-06-18 11:17:20 +0100 (Mon, 18 Jun 2007) | 1 line Various License header updates. ........ r548302 | ritchiem | 2007-06-18 11:49:50 +0100 (Mon, 18 Jun 2007) | 2 lines Various License header updates. Update to PrincipalDatabase's to ensure they work correctly with # comments. ........ r548308 | ritchiem | 2007-06-18 11:58:38 +0100 (Mon, 18 Jun 2007) | 1 line Various License header updates, missed this file. Though the first update of it via the JMX console will remove the license. ........ r548312 | rupertlssmith | 2007-06-18 12:03:09 +0100 (Mon, 18 Jun 2007) | 1 line Added SLF4J to Log4J binding. ........ r548315 | ritchiem | 2007-06-18 12:07:45 +0100 (Mon, 18 Jun 2007) | 1 line Old lib dir from M1 ........ r548317 | ritchiem | 2007-06-18 12:13:57 +0100 (Mon, 18 Jun 2007) | 1 line Old lib dirs from M1 ........ r548319 | ritchiem | 2007-06-18 12:16:25 +0100 (Mon, 18 Jun 2007) | 1 line Mistakenly checked in Intelij file ........ r548381 | ritchiem | 2007-06-18 16:37:41 +0100 (Mon, 18 Jun 2007) | 1 line QPID-525 Memory leak in DestWildExchange. Used routing key in remove rather than empty queue ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@548400 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/PingSendOnlyClient.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java index ed0ac49ef9..bbe337ca0a 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java @@ -1,3 +1,24 @@ +/* + * + * 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.qpid.ping; import java.util.Properties; -- cgit v1.2.1 From 4fbd28b6078d6b3fbfe528a99d6e27963c68f99b Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Tue, 31 Jul 2007 15:53:37 +0000 Subject: Merged revisions 1-447993,447995-448007,448009-448141,448143-448157,448161-448194,448196-448210,448212-448218,448220-448223,448225-448233,448235,448237-448241,448243-448596,448598-448623,448625-448850,448852-448880,448882-448982,448984-449635,449637-449639,449641-449642,449644-449645,449647-449674,449676-449719,449721-449749,449751-449762,449764-449933,449935-449941,449943-450383,450385,450387-450400,450402-450433,450435-450503,450505-450555,450557-450860,450862-451024,451026-451149,451151-451316,451318-451931,451933-452139,452141-452162,452164-452320,452322,452324-452325,452327-452333,452335-452429,452431-452528,452530-452545,452547-453192,453194-453195,453197-453536,453538,453540-453656,453658-454676,454678-454735,454737,454739-454781,454783-462728,462730-462819,462821-462833,462835-462839,462841-463071,463073-463178,463180-463308,463310-463362,463364-463375,463377-463396,463398-463402,463404-463409,463411-463661,463663-463670,463672-463673,463675-464493,464495-464502,464504-464576,464578-464613,464615-464628,464630,464632-464866,464868-464899,464901-464942,464944-464949,464951-465004,465006-465016,465018-465053,465055-465165,465167-465321,465323-465406,465408-465427,465429-465431,465433-465548,465550-466044,466047-466075,466077,466079-466081,466083-466099,466101-466112,466114-466126,466128-466240,466242-466971,466973-466978,466980-467309,467311-467312,467316-467328,467330-467485,467487-467588,467590-467604,467606-467699,467701-467706,467708-467749,467751-468069,468071-468537,468539-469241,469244-469246,469248-469318,469320-469421,469423,469425-469429,469431-469435,469437-469462,469464-469469,469472-469477,469479-469490,469492-469503,469505-469529,469531-469598,469600-469624,469626-469737,469739-469752,469754-469806,469808-469928,469930-469953,469955-470011,470013-470109,470111-470335,470338-470339,470341-470379,470381,470383-470399,470401-470446,470448-470741,470743-470758,470760-470809,470811-470817,470819-470993,470995-471001,471003-471788,471790-471792,471794-472028,472030-472032,472034-472036,472038,472040,472043,472045-472059,472061,472063,472065-472066,472068,472070-472072,472074-472080,472082,472084-472092,472094-472107,472109-472123,472125-472158,472160-472165,472167-472172,472174-472457,472459-472460,472462-472464,472466-472470,472472-472483,472486-472491,472493-472494,472496-472497,472499,472501-472503,472505-472512,472514-472544,472546-472556,472558-472560,472562-472572,472574-472587,472589-472591,472593-472605,472607,472609-472731,472733-472786,472788-472843,472845-472849,472851-472859,472861-472878,472880-472903,472905,472907-472988,472990-472991,472993-473071,473073-473086,473088-473090,473093,473095-473096,473098-473106,473108-473110,473112-473185,473187-473260,473262,473268-473270,473275-473279,473281,473284-473287,473289-473295,473297-473306,473308-473330,473332-473335,473337,473339-473344,473346-473351,473353-473355,473357-473358,473361-473471,473473-473497,473499-473535,473537-473567,473569-473888,473890-474451,474454-474492,474494-474563,474565-474843,474845-474865,474867-474932,474934-475035,475037-475144,475146-475180,475182-475265,475267-475285,475287,475289-475293,475295-475296,475298-475302,475304-475631,475633-475649,475651-475748,475750-475752,475754-476107,476109-476302,476304-476413,476415-476430,476432-476700,476702-476868,476870-477147,477149-477213,477215-477263,477265-477340,477342-477635,477637-477789,477791-477825,477827-477841,477843,477846-477852,477854,477856,477858-477865,477867-477894,477896-478022,478024-478182,478184-478211,478213-478233,478235-478236,478238-478241,478243-478252,478254-478259,478261-478263,478265,478267-478269,478271-478286,478288-478342,478344-478379,478381-478412,478414-478443,478445-478636,478639-478658,478660-478821,478823-478853,478855-478922,478924-478962,478965-478974,478976-479029,479031-479049,479051-479210,479212-479214,479216-479407,479409-479415,479417-479425,479427-479559,479561-479639,479641-479676,479678-479685,479687-480030,480033-480086,480091-480093,480095-480118,480120-480139,480141,480143-480148,480150-480156,480158-480163,480165-480177,480179-480189,480191-480193,480195-480198,480200-480220,480222-480282,480284-480292,480294-480308,480310-480317,480320-480422,480424,480426-480581,480583-480656,480658-480692,480695-480702,480704,480706-480710,480712-480910,480913-480933,480935-480945,480947-480972,480974-480993,480995-481034,481036-481158,481161-481174,481176-481220,481222-481234,481236-481260,481263-481264,481266-481296,481298-481304,481306-481311,481313-481332,481334,481336-481380,481382-481441,481443-482144,482146-482180,482182-482193,482195-482232,482234-482236,482239,482241-482242,482244-482247,482250-482251,482253,482256-482261,482264-482288,482290-482364,482366,482368,482370-482554,482556,482558-482569,482572-482636,482638,482640-482696,482698-482722,482724-482732,482734-482771,482774-482957,482959-483045,483047-483105,483108,483110-483115,483117,483119-483127,483130-483134,483136-483148,483150-483158,483160-483164,483166-483178,483180-483391,483393-483400,483402-483403,483405-483418,483420-483421,483425-483436,483438-483470,483472-483502,483504-483558,483560-483599,483601-483637,483639-483644,483646-483659,483661-483670,483672-483878,483880-483910,483912-483915,483917-483940,483942,483944-483968,483970-483972,483974-483976,483978,483980-484612,484614-484657,484659-484693,484695-484718,484720-484842,484844-484847,484849-484986,484988-485019,485021-485489,485491-485544,485546-485591,485593,485595-485697,485699-485729,485731-485734,485736-485779,485781-485787,485789-485851,485853,485855-486007,486009,486011-486020,486022-486083,486085-486097,486099-486117,486120-486131,486133-486148,486150-486161,486163-486164,486166-486197,486199-486205,486208-486247,486249-486253,486256-486427,486429-486431,486433-486554,486556-486573,486575-486593,486595,486597-486609,486611-486619,486622,486625,486627-486641,486643-486645,486649-486687,486689-486721,486723-486730,486732-486746,486748-486759,486761,486763-486777,486779-486782,486784-486788,486790,486792,486794-486796,486798-487175,487178,487180-487213,487215,487217-487267,487269-487284,487286-487298,487300-487358,487360-487367,487369-487382,487384-487434,487436-487480,487482-487547,487549-487561,487563-487565,487567-487578,487580-487615,487617-487622,487624,487626,487628,487630-487635,487637-487703,487705-487777,487780-487781,487783-487800,487802-487803,487805-487820,487822-487848,487850-487902,487904-488103,488105-488133,488135-488158,488160-488163,488165-488187,488189-488216,488218-488248,488250-488278,488280,488282-488303,488305-488313,488315-488342,488344-488351,488353-488376,488378-488449,488451-488593,488595,488597-488623,488625-488700,488702-488704,488706-488710,488714,488716-488725,488727-488744,488746-488770,488772-488798,488800,488802-488807,488809,488811-488829,488831-488843,488845-488851,488853-489069,489071-489077,489079-489081,489084-489102,489104-489105,489107-489109,489111-489112,489114-489139,489141-489178,489181-489203,489205-489211,489213,489216-489329,489332-489402,489404-489417,489419-489421,489423-489643,489645-489690,489692-489703,489705-489714,489716-489747,489749-489753,489755-489803,489805-489904,489906-490372,490374-490504,490506-490604,490606-490707,490710-490733,490735-490871,490873-490984,490986-491028,491030,491032-491071,491073-491119,491121-491576,491578-491672,491674-491800,491802-491838,491840-491878,491880-492183,492185-492279,492281-492317,492319-492513,492515-492584,492586-492587,492589-492601,492603-492635,492637-492640,492642-492717,492719-492723,492725-492729,492731-492755,492757-492901,492903-492955,492957-492962,492964-492997,492999-493002,493004-493041,493043-493059,493062-493063,493065-493086,493088-493125,493127-493139,493141-493150,493152-493871,493873-494017,494019-494030,494032-494041,494043-494091,494093-494120,494122-494354,494356-494436,494438-494539,494541-494552,494554-494586,494588-494649,494651,494653-494654,494656-494657,494659-494764,494766-494768,494770-494796,494798-494799,494802,494804-494860,494862-494903,494905-494906,494908-495019,495021-495160,495162-495168,495171-495188,495190-495229,495231-495254,495256-495303,495305-495313,495315-495336,495338-495372,495374-495379,495381-495454,495457-495459,495462-495516,495518-495524,495526-495531,495533-495548,495551-495553,495555,495557-495558,495560,495562-495573,495575-495583,495585-495594,495596-495628,495630-495638,495640-495651,495653-495660,495662-495753,495755-496259,496261-496262,496264-496269,496271-496275,496277-496301,496303-496316,496318-496383,496385-496413,496415-496495,496497-496625,496627-496636,496638-496640,496642-496647,496650-496657,496659-496660,496663-496664,496666-496677,496679-496681,496683-496730,496732-496750,496752,496754-496784,496786-496832,496834-496840,496842-496990,496992-496995,496997-497340,497343-497351,497353-497403,497405-497424,497426-497438,497440-497481,497483-497497,497499-497765,497767-497769,497771-497775,497777-497778,497780,497782-497783,497785,497787-497812,497814-497871,497873-497877,497879-498573,498575-498588,498590,498592,498594-498636,498638-498669,498671-498686,498688-498689,498691-498719,498721-498964,498966-498969,498971-498973,498975-498982,498985-499035,499037-499040,499042,499044-499048,499050-499082,499084-499086,499088-499164,499167-499169,499171-499355,499357-499370,499372-499373,499375-499391,499393,499395-499425,499428,499430-499445,499447-499455,499457-499460,499462-499465,499467,499469-499489,499491-499492,499494-499531,499533-499562,499566-499627,499629-499715,499717-499732,499734-499755,499758-499763,499765-499780,499782-499795,499797-499802,499804-499844,499846,499848-499850,499852-499863,499865-499873,499875-499974,499976-499978,499980-500263,500265-500283,500285-500309,500311-501000,501002,501012-501057,501059-501095,501097-501390,501392-501410,501413-501447,501449-501454,501456,501458-501464,501466-501471,501473-501803,501805-501913,501915-501916,501918-501919,501921-501944,501946-502171,502173-502177,502181,502183-502247,502250-502252,502254-502260,502262-502267,502270,502272,502274-502575,502577-502609,502611-502619,502621-502626,502628-502654,502656-503592,503594-503603,503605-503608,503610-503636,503638-503645,503647-503705,503707-503789,503791-504024,504026-504111,504113-504506,504508-504735,504737-504863,504865-504867,504869-504914,504916-505241,505243-505254,505257-505267,505269-505354,505356-505891,505893-505971,505973-506400,506402-506404,506407-506438,506440-506516,506518-506541,506543-506966,506968-506971,506973-507095,507097-507108,507111-507454,507456,507459-507471,507473-507556,507558,507560-507581,507585-507594,507597,507599-507608,507610-507728,507730-507893,507895-507937,507940-508234,508236-508350,508352-508365,508367-508380,508383,508386-508415,508417-508648,508650-508941,508943-509146,509148-509171,509173-509175,509179-509201,509203-509207,509209-509215,509217-509222,509224-509477,509480-509627,509629-509634,509636-509641,509643-509736,509738-509931,509933-510059,510061-510075,510077-510158,510161-510896,510898-510938,510940-511388,511390-511922,511924-512287,512289-512698,512702-512813,512815-512817,512819-513359,513361-513370,513372-514702,514704-514886,514888-514902,514904-515126,515129-515141,515143-515516,515518-515534,515536-515538,515540-515648,515650-515651,515653-516070,516072-516411,516413-516448,516450,516452-517637,517639-517647,517649-517659,517661-517663,517665-517677,517679-517682,517684-517744,517746-518085,518087-518175,518177-518558,518560-518568,518571-518666,518668,518670-518699,518701-518987,518990-518992,518994-519908,519910-519932,519934-520414,520416-520842,520844-520937,520939-521362,521364-521681,521683-521704,521706-521709,521711-521714,521716-521781,521783-521792,521794-522462,522464-522527,522529-522534,522536-522566,522568-522958,522960,522962-522966,522968-522976,522978-522980,522982-522988,522992-522993,522995-523244,523246-523746,523748-524049,524051-524738,524741-524742,524744-524762,524764,524766,524768-525486,525488-525530,525532,525534,525537-525552,525554-525765,525767-525776,525778-525784,525789-525803,525805-525816,525818-525828,525830-525861,525863-525866,525868-526090,526092-526112,526114-526116,526119-526121,526123-526149,526151-526153,526155-526156,526160-526165,526167-526186,526188-526193,526196-526197,526200-526665,526667-526682,526686-526690,526693,526695-526708,526710-526713,526715-526775,526777-526802,526804-526806,526808-527048,527051-527052,527054-527181,527183-527486,527488-527492,527494-527498,527500-527508,527510-527517,527519-527536,527538-527555,527559-527802,527804-527842,527844-527847,527849-527875,527877-527940,527942-527958,527960-527971,527973-528002,528004,528006-528423,528425-529232,529234-529245,529247-529296,529298-529634,529636-529658,529660-529665,529667-529668,529670-530033,530035-530036,530038-530040,530045-530046,530050-530051,530053-530431,530433-530436,530439-530440,530443,530445-530446,530448,530450-530682,530684,530687-530696,530698-530733,530735-530776,530778-530795,530799,530801-530811,530813-530818,530820-530837,530839-531436,531438-531455,531457,531459-531511,531514,531516,531519-531523,531525,531528-531858,531860-531864,531866-531907,531909-531916,531918-531936,531938-531988,531990-532001,532003-532371,532373-532465,532467-532727,532729-532765,532767-532785,532788-532790,532792-532793,532795-533064,533066-533074,533076,533080-533130,533132-533139,533142-533703,533705-533720,533722-533763,533766-533818,533820-533839,533841-533859,533862-534035,534037-534112,534114-534116,534118-534472,534474-534477,534479-534762,534764-534896,534898-534902,534904-535253,535255-535308,535310-535808,535810-535873,535875-536007,536009-536140,536142-536162,536165-536242,536244-536252,536254-536278,536280-536338,536340-536448,536450-536479,536481-536482,536484-536485,536487-536495,536497,536500-536505,536507-536561,536563-536570,536572,536574-536583,536586-536823,536825-537014,537016-537018,537020-537025,537027-537028,537030-537160,537162-537170,537172-537672,537674-537781,537783-537833,537836-537840,537842-537844,537846-537953,537955-538034,538036-538078,538080-538083,538085-538097,538099-538108,538110-538239,538241-538881,538883-538906,538908-538911,538913-538921,538923-539177,539179-539190,539192-539469,539471-539475,539477-539480,539482-539483,539485-539500,539502-539593,539595-539782,539784-539787,539789-540106,540108-540168,540170-540510,540512-541246,541248-542483,542485-542788,542790-543495,543497-544108,544110-544421,544423-544507,544509-544865,544867-545145,545147-546095,546097-546189,546191-546440,546442-546457,546459-547177,547179-547626,547628-548275,548277-548278,548280-548301,548303-548307,548309-548311,548313-548314,548316,548318,548320-548380,548382-549010,549012-549529,549531-549848,549850-550508,550510-550747,550749-550772,550774-550848,550850-551116,551122-553446,553448-561282 via svnmerge from https://svn.apache.org/repos/asf/incubator/qpid/branches/M2 ........ r541920 | tomasr | 2007-05-26 18:35:51 +0100 (Sat, 26 May 2007) | 1 line QPID-136 Initial Prefetch Implementation ........ r549112 | arnaudsimon | 2007-06-20 15:11:03 +0100 (Wed, 20 Jun 2007) | 1 line changed setText to use UTF8 as default encoder ........ r551167 | arnaudsimon | 2007-06-27 15:08:50 +0100 (Wed, 27 Jun 2007) | 1 line added public void declareAndBind(AMQDestination amqd) ........ r551174 | ritchiem | 2007-06-27 15:23:21 +0100 (Wed, 27 Jun 2007) | 3 lines Caused each of these tests to run 10 times to help identify any race conditions that were occuring. Updated the CommitRollbackTest to be more robust in the detection of failure. ........ r551175 | ritchiem | 2007-06-27 15:23:52 +0100 (Wed, 27 Jun 2007) | 1 line Allowed more of the constants to be set via system properties. ........ r551176 | ritchiem | 2007-06-27 15:25:13 +0100 (Wed, 27 Jun 2007) | 1 line renamed the passwd programme qpid-passwd to match the change in bin directory. ........ r552441 | rupertlssmith | 2007-07-02 10:23:54 +0100 (Mon, 02 Jul 2007) | 1 line Added log4j as slfj logger for perftests. ........ r552499 | rupertlssmith | 2007-07-02 15:17:45 +0100 (Mon, 02 Jul 2007) | 1 line Added some documentation. ........ r553172 | rupertlssmith | 2007-07-04 12:11:04 +0100 (Wed, 04 Jul 2007) | 1 line Messages moved by management console now commited on the message store. ........ r553248 | ritchiem | 2007-07-04 17:05:55 +0100 (Wed, 04 Jul 2007) | 6 lines Addition of the MessageStore Tool. Small changes to the Exchanges to allow the extraction of currently listed items. Extracted initial broker configuration mechanism to a reusable class. Have modified broker to use it. Move the Passwd.java to new tools package structure on the broker. ........ r553265 | ritchiem | 2007-07-04 17:42:59 +0100 (Wed, 04 Jul 2007) | 1 line Tidied up some extranious logging. ........ r553432 | rupertlssmith | 2007-07-05 10:28:33 +0100 (Thu, 05 Jul 2007) | 1 line Fixed test state carrying over to mandatory message test from immediate. Also added in-vm clean up to other tests. ........ r553480 | ritchiem | 2007-07-05 13:40:50 +0100 (Thu, 05 Jul 2007) | 2 lines Minor changes and tidy up when running via command line. Added Copy command. ........ r553482 | ritchiem | 2007-07-05 13:44:42 +0100 (Thu, 05 Jul 2007) | 2 lines Forgot to compile before committing. Missed a method change in the Select command. ........ r554964 | rupertlssmith | 2007-07-10 15:40:04 +0100 (Tue, 10 Jul 2007) | 1 line Added message copy method. ........ r555249 | rupertlssmith | 2007-07-11 12:52:39 +0100 (Wed, 11 Jul 2007) | 1 line Update perftests to center better around current performance. ........ r556011 | rupertlssmith | 2007-07-13 15:24:03 +0100 (Fri, 13 Jul 2007) | 1 line Moved test framework into its own package and cleaned it up. ........ r556024 | rupertlssmith | 2007-07-13 16:02:06 +0100 (Fri, 13 Jul 2007) | 1 line Completed javadoc for test framework. ........ r556628 | rgodfrey | 2007-07-16 14:50:57 +0100 (Mon, 16 Jul 2007) | 1 line QPID-537 : Make AMQMessage.incrementReference public ........ r556675 | cctrieloff | 2007-07-16 18:36:21 +0100 (Mon, 16 Jul 2007) | 2 lines added notice entries ........ r556680 | cctrieloff | 2007-07-16 18:56:40 +0100 (Mon, 16 Jul 2007) | 2 lines clean up ........ r556682 | cctrieloff | 2007-07-16 18:58:37 +0100 (Mon, 16 Jul 2007) | 2 lines removed optional cppunit as not in distributed packages ........ r556845 | ritchiem | 2007-07-17 09:26:33 +0100 (Tue, 17 Jul 2007) | 3 lines Additional logging in case of broker failure at startup. Use broker logger at error level as well as System.out ........ r556847 | ritchiem | 2007-07-17 09:35:35 +0100 (Tue, 17 Jul 2007) | 3 lines Update to the MessageStore Tool to provide Move and Purge functionality. Updated to remove the AMQExceptions that will be removed from the Exchange class. ........ r556861 | ritchiem | 2007-07-17 10:26:47 +0100 (Tue, 17 Jul 2007) | 2 lines QPID-538 Check to ensure a duplicate binding is not created. ........ r556868 | ritchiem | 2007-07-17 10:55:56 +0100 (Tue, 17 Jul 2007) | 1 line Addition of simple pub/sub examples. ........ r556869 | ritchiem | 2007-07-17 10:56:17 +0100 (Tue, 17 Jul 2007) | 1 line QPID-540 Prevent NPE when purging message from the main _message queue in the ConcurrentSelectorDeliveryManager that have been delivered via a Subscribers _messageQueue. Ensuring that any expired messages are still correctly handled. i.e. the Queue size/depth is reduced and the message correctly dequeued from the underlying store. ........ r556871 | ritchiem | 2007-07-17 10:57:35 +0100 (Tue, 17 Jul 2007) | 1 line White space & code formatting change ........ r556872 | ritchiem | 2007-07-17 10:58:35 +0100 (Tue, 17 Jul 2007) | 3 lines Added additional information to hard-error logging in exceptionReceived. Fully expanded imports ........ r556888 | ritchiem | 2007-07-17 12:33:08 +0100 (Tue, 17 Jul 2007) | 1 line Change to allow the management port to be specified on the command line, via -m or --mport ........ r556890 | ritchiem | 2007-07-17 12:38:10 +0100 (Tue, 17 Jul 2007) | 4 lines QPID-541 A large portion of memory was being wasted in 32k ByteBuffers being held by the AMQShortStrings. Patch submitted by Robert Godfrey to intern() the AMQSSs to reduce memory usage. Current implementation *will* impact performance due to the usage of a static Map for storage. However, a thread local implementation is in the works. ........ r556898 | rgodfrey | 2007-07-17 13:00:57 +0100 (Tue, 17 Jul 2007) | 1 line QPID-541 : Change to use threadlocal maps for intern for the common case to avoid excessive synchronization. In the uncommon case will require more lookup. ........ r556958 | rupertlssmith | 2007-07-17 17:22:16 +0100 (Tue, 17 Jul 2007) | 1 line Refactored the distributed test clients and coordinator to support different distribution and sequencing engines. ........ r556967 | rupertlssmith | 2007-07-17 17:40:14 +0100 (Tue, 17 Jul 2007) | 1 line Removed unused package. ........ r556968 | rupertlssmith | 2007-07-17 17:42:00 +0100 (Tue, 17 Jul 2007) | 1 line Retired old interop tests. ........ r556969 | rupertlssmith | 2007-07-17 17:43:49 +0100 (Tue, 17 Jul 2007) | 1 line Properties file not needed any more. Test properties all driven from MessagingTestConfigProperties. ........ r557276 | ritchiem | 2007-07-18 15:36:11 +0100 (Wed, 18 Jul 2007) | 1 line Updates to pom files and Licensing/Notice files for M2 release. ........ r557279 | ritchiem | 2007-07-18 15:51:42 +0100 (Wed, 18 Jul 2007) | 1 line This is left over from ANT ........ r557281 | ritchiem | 2007-07-18 15:54:06 +0100 (Wed, 18 Jul 2007) | 1 line updated comment to refelect property values ........ r557286 | ritchiem | 2007-07-18 16:02:22 +0100 (Wed, 18 Jul 2007) | 1 line Set default mvn build to assembly:assembly ........ r557288 | ritchiem | 2007-07-18 16:09:07 +0100 (Wed, 18 Jul 2007) | 1 line Ensure the top level release-docs directory is included in the builds ........ r557306 | ritchiem | 2007-07-18 17:01:58 +0100 (Wed, 18 Jul 2007) | 1 line Update fix incorrect license headers. ........ r557312 | ritchiem | 2007-07-18 17:07:01 +0100 (Wed, 18 Jul 2007) | 1 line added license ........ r557314 | ritchiem | 2007-07-18 17:11:17 +0100 (Wed, 18 Jul 2007) | 1 line added license ........ r557452 | aconway | 2007-07-19 03:03:02 +0100 (Thu, 19 Jul 2007) | 14 lines * lib/broker/Daemon.cpp, .h - Rewrote to remove libdaemon dependency. - PID file stored in /var/run if root, /tmp otherwise. * src/qpidd.cpp: Use new Daemon.cpp. - lock files stored in /var/run (for root) or /tmp. - updated to trunk daemon flag behavior. * lib/broker/Makefile.am (libqpidbroker_la_LIBADD): - Daemon.cpp now needs -lboost_iostreams * NOTICE, README: Removed mention of libdaemon. ........ r558027 | ritchiem | 2007-07-20 17:08:05 +0100 (Fri, 20 Jul 2007) | 1 line Added a logger but only used to control the toString inclusion of password. If in debug mode it will include password otherwise the password is "********". ........ r558072 | astitcher | 2007-07-20 18:49:41 +0100 (Fri, 20 Jul 2007) | 2 lines Fixed the license from the "old" apache copyright notice ........ r558083 | aconway | 2007-07-20 19:29:08 +0100 (Fri, 20 Jul 2007) | 2 lines Remove -ldaemon, we no longer require libdaemon. ........ r558099 | aconway | 2007-07-20 20:20:01 +0100 (Fri, 20 Jul 2007) | 2 lines Ignore QPID_ env variables that don't correspond to known options. ........ r558108 | cctrieloff | 2007-07-20 20:55:40 +0100 (Fri, 20 Jul 2007) | 2 lines typo fix ........ r558114 | rajith | 2007-07-20 21:11:03 +0100 (Fri, 20 Jul 2007) | 1 line added release notes ........ r558115 | rajith | 2007-07-20 21:12:20 +0100 (Fri, 20 Jul 2007) | 1 line Checking in the release notes ........ r558116 | aconway | 2007-07-20 21:16:20 +0100 (Fri, 20 Jul 2007) | 3 lines Removed .txt from RELEASE_NOTES Added RELEASE_NOTES to EXTRA_DIST in Makefile.am ........ r558168 | rajith | 2007-07-20 23:03:42 +0100 (Fri, 20 Jul 2007) | 1 line added release notes ........ r558170 | rajith | 2007-07-20 23:04:11 +0100 (Fri, 20 Jul 2007) | 1 line added release notes ........ r558630 | gsim | 2007-07-23 08:21:49 +0100 (Mon, 23 Jul 2007) | 3 lines Revised release notes: removed bug fixed on this branch, removed outstanding feature lists as it is not terribly accurate or helpful. ........ r559419 | rupertlssmith | 2007-07-25 13:17:59 +0100 (Wed, 25 Jul 2007) | 1 line Refactored interop tests into general distributed test framework. Moved framework under systests from integrationtests. ........ r559427 | ritchiem | 2007-07-25 13:40:24 +0100 (Wed, 25 Jul 2007) | 2 lines AMQMessage - added //todo-s and removed unused parameter StoreContext from expired() method call. ConcurrentSelectorDeliveryManager - Update to reflect expired() call change. Created new _reaperContextStore to be used when performing reaper operations such as message dequeue due to expiration. Removed old commented code. ........ r559455 | rupertlssmith | 2007-07-25 14:40:16 +0100 (Wed, 25 Jul 2007) | 1 line Added to comments. ........ r559456 | rupertlssmith | 2007-07-25 14:41:21 +0100 (Wed, 25 Jul 2007) | 1 line Removed redundant method. ........ r559458 | rupertlssmith | 2007-07-25 14:57:21 +0100 (Wed, 25 Jul 2007) | 1 line Refactored packaging of test framework. ........ r559461 | rupertlssmith | 2007-07-25 15:00:16 +0100 (Wed, 25 Jul 2007) | 1 line Removed redundant packages. ........ r559943 | rhs | 2007-07-26 20:15:17 +0100 (Thu, 26 Jul 2007) | 1 line adding missing ack ........ r559944 | rhs | 2007-07-26 20:15:44 +0100 (Thu, 26 Jul 2007) | 1 line removed old script ........ r560198 | ritchiem | 2007-07-27 12:30:34 +0100 (Fri, 27 Jul 2007) | 1 line Added files to ignore list ........ r560225 | ritchiem | 2007-07-27 14:33:50 +0100 (Fri, 27 Jul 2007) | 1 line Converted namespaces from Qpid.* to Apache.Qpid.* ........ r560471 | tomasr | 2007-07-28 03:35:41 +0100 (Sat, 28 Jul 2007) | 1 line Removed using directives causing compilation failure in .NET 1.1 ........ r561278 | ritchiem | 2007-07-31 10:07:57 +0100 (Tue, 31 Jul 2007) | 8 lines Changes to POMs. Client pom now builds a single jar with all dependancies included in the single bundle. systests/pom.xml adjusted to include only *Test.class items. This will fix the current Error on OptOutTestCase management/eclipse-plugin/pom.xml - editied to include there required MANIFEST.MF to identify plugin to eclipse distribution/src/main/assembly/management-eclipse-plugin.xml editied to include there required MANIFEST.MF to identify the plugin distribution/pom.xml - white space Also updated log4j.xml default to create an alert.log file from the AMQQueue alerting. Added a debug.log4j.xml that gives example of debugging the broker via log4j. ........ git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@561365 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/message/TestMessageFactory.java | 25 +++++++++------- .../org/apache/qpid/ping/PingDurableClient.java | 27 +++++++++-------- .../org/apache/qpid/ping/PingSendOnlyClient.java | 2 +- .../apache/qpid/requestreply/PingPongProducer.java | 35 +++++++++++----------- 4 files changed, 46 insertions(+), 43 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java index eeb4021f34..64ccb719b6 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java @@ -1,18 +1,21 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * 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 * - * Licensed 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 * - * 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. + * 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.qpid.client.message; diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java index 2765986868..c5f71b4774 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java @@ -20,18 +20,6 @@ */ package org.apache.qpid.ping; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.jms.Destination; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.jms.Message; - import org.apache.log4j.Logger; import org.apache.qpid.requestreply.PingPongProducer; @@ -40,6 +28,18 @@ import org.apache.qpid.util.CommandLineParser; import uk.co.thebadgerset.junit.extensions.util.MathUtils; import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; +import javax.jms.Destination; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; + /** * PingDurableClient is a variation of the {@link PingPongProducer} ping tool. Instead of sending its pings and * receiving replies to them at the same time, this tool sends pings until it is signalled by some 'event' to stop @@ -167,7 +167,8 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList try { // Create a ping producer overriding its defaults with all options passed on the command line. - Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); + Properties options = + CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); PingDurableClient pingProducer = new PingDurableClient(options); // Create a shutdown hook to terminate the ping-pong producer. diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java index bbe337ca0a..2879f0c322 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java @@ -57,7 +57,7 @@ public class PingSendOnlyClient extends PingDurableClient try { // Create a ping producer overriding its defaults with all options passed on the command line. - Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); PingSendOnlyClient pingProducer = new PingSendOnlyClient(options); // Create a shutdown hook to terminate the ping-pong producer. diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index d5d1c304e9..03f5f0549d 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -20,20 +20,6 @@ */ package org.apache.qpid.requestreply; -import java.io.IOException; -import java.net.InetAddress; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import javax.jms.*; - import org.apache.log4j.Logger; import org.apache.qpid.AMQException; @@ -51,6 +37,18 @@ import uk.co.thebadgerset.junit.extensions.BatchedThrottle; import uk.co.thebadgerset.junit.extensions.Throttle; import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; +import javax.jms.*; + +import java.io.IOException; +import java.net.InetAddress; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + /** * PingPongProducer is a client that sends test messages, and waits for replies to these messages. The replies may * either be generated by another client (see {@link PingPongBouncer}, or an extension of it may be used that listens @@ -89,7 +87,7 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; *
    destinationCount 1 The number of receivers listening to the pings. *
    timeout 30000 In milliseconds. The timeout to stop waiting for replies. *
    commitBatchSize 1 The number of messages per transaction in transactional mode. - *
    uniqueDests true Whether each receiver only listens to one ping destination or all. + *
    uniqueDests true Whether each receivers only listens to one ping destination or all. *
    durableDests false Whether or not durable destinations are used. *
    ackMode AUTO_ACK The message acknowledgement mode. Possible values are: * 0 - SESSION_TRANSACTED @@ -237,7 +235,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Holds the default message selector. */ public static final String SELECTOR_DEFAULT = ""; - /** Holds the name of the proeprty to get the destination count from. */ + /** Holds the name of the property to get the destination count from. */ public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; /** Defines the default number of destinations to ping. */ @@ -373,7 +371,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis protected int _maxPendingSize; /** - * Holds a monitor which is used to synchronize sender and receiver threads, where the sender has elected + * Holds a monitor which is used to synchronize sender and receivers threads, where the sender has elected * to wait until the number of unreceived message is reduced before continuing to send. */ protected Object _sendPauseMonitor = new Object(); @@ -570,7 +568,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { try { - Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); + Properties options = + CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); // Create a ping producer overriding its defaults with all options passed on the command line. PingPongProducer pingProducer = new PingPongProducer(options); -- cgit v1.2.1 From c06860ce45b4f52be1ba934fd4d92da10c9cc25f Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 31 Jul 2007 22:34:12 +0000 Subject: Rolled back revision 561365 and commented out some broken code in ClientSession.java. The trunk should now build. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@561578 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/message/TestMessageFactory.java | 25 +++++++--------- .../org/apache/qpid/ping/PingDurableClient.java | 27 ++++++++--------- .../org/apache/qpid/ping/PingSendOnlyClient.java | 2 +- .../apache/qpid/requestreply/PingPongProducer.java | 35 +++++++++++----------- 4 files changed, 43 insertions(+), 46 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java index 64ccb719b6..eeb4021f34 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java @@ -1,21 +1,18 @@ /* * - * 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 + * Copyright (c) 2006 The Apache Software Foundation * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed 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 * - * 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. + * 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.qpid.client.message; diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java index c5f71b4774..2765986868 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java @@ -20,6 +20,18 @@ */ package org.apache.qpid.ping; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Destination; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; + import org.apache.log4j.Logger; import org.apache.qpid.requestreply.PingPongProducer; @@ -28,18 +40,6 @@ import org.apache.qpid.util.CommandLineParser; import uk.co.thebadgerset.junit.extensions.util.MathUtils; import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; -import javax.jms.Destination; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.jms.Message; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicInteger; - /** * PingDurableClient is a variation of the {@link PingPongProducer} ping tool. Instead of sending its pings and * receiving replies to them at the same time, this tool sends pings until it is signalled by some 'event' to stop @@ -167,8 +167,7 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList try { // Create a ping producer overriding its defaults with all options passed on the command line. - Properties options = - CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); PingDurableClient pingProducer = new PingDurableClient(options); // Create a shutdown hook to terminate the ping-pong producer. diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java index 2879f0c322..bbe337ca0a 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java @@ -57,7 +57,7 @@ public class PingSendOnlyClient extends PingDurableClient try { // Create a ping producer overriding its defaults with all options passed on the command line. - Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); PingSendOnlyClient pingProducer = new PingSendOnlyClient(options); // Create a shutdown hook to terminate the ping-pong producer. diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 03f5f0549d..d5d1c304e9 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -20,6 +20,20 @@ */ package org.apache.qpid.requestreply; +import java.io.IOException; +import java.net.InetAddress; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.*; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; @@ -37,18 +51,6 @@ import uk.co.thebadgerset.junit.extensions.BatchedThrottle; import uk.co.thebadgerset.junit.extensions.Throttle; import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; -import javax.jms.*; - -import java.io.IOException; -import java.net.InetAddress; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - /** * PingPongProducer is a client that sends test messages, and waits for replies to these messages. The replies may * either be generated by another client (see {@link PingPongBouncer}, or an extension of it may be used that listens @@ -87,7 +89,7 @@ import java.util.concurrent.atomic.AtomicLong; *
    destinationCount 1 The number of receivers listening to the pings. *
    timeout 30000 In milliseconds. The timeout to stop waiting for replies. *
    commitBatchSize 1 The number of messages per transaction in transactional mode. - *
    uniqueDests true Whether each receivers only listens to one ping destination or all. + *
    uniqueDests true Whether each receiver only listens to one ping destination or all. *
    durableDests false Whether or not durable destinations are used. *
    ackMode AUTO_ACK The message acknowledgement mode. Possible values are: * 0 - SESSION_TRANSACTED @@ -235,7 +237,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Holds the default message selector. */ public static final String SELECTOR_DEFAULT = ""; - /** Holds the name of the property to get the destination count from. */ + /** Holds the name of the proeprty to get the destination count from. */ public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; /** Defines the default number of destinations to ping. */ @@ -371,7 +373,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis protected int _maxPendingSize; /** - * Holds a monitor which is used to synchronize sender and receivers threads, where the sender has elected + * Holds a monitor which is used to synchronize sender and receiver threads, where the sender has elected * to wait until the number of unreceived message is reduced before continuing to send. */ protected Object _sendPauseMonitor = new Object(); @@ -568,8 +570,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { try { - Properties options = - CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); // Create a ping producer overriding its defaults with all options passed on the command line. PingPongProducer pingProducer = new PingPongProducer(options); -- cgit v1.2.1 From 44c1d81cde128c90e75c9e026762d1ca926e2d0c Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Thu, 23 Aug 2007 12:10:42 +0000 Subject: updated from M2 branch git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@568952 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/message/TestMessageFactory.java | 25 +- .../org/apache/qpid/ping/PingAsyncTestPerf.java | 292 +++++++++++++ .../main/java/org/apache/qpid/ping/PingClient.java | 25 +- .../org/apache/qpid/ping/PingDurableClient.java | 38 +- .../org/apache/qpid/ping/PingLatencyTestPerf.java | 314 ++++++++++++++ .../org/apache/qpid/ping/PingSendOnlyClient.java | 2 +- .../java/org/apache/qpid/ping/PingTestPerf.java | 196 +++++++++ .../apache/qpid/requestreply/PingPongBouncer.java | 10 +- .../apache/qpid/requestreply/PingPongProducer.java | 478 +++++++++++++-------- .../apache/qpid/requestreply/PingPongTestPerf.java | 251 +++++++++++ 10 files changed, 1419 insertions(+), 212 deletions(-) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java index eeb4021f34..64ccb719b6 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java @@ -1,18 +1,21 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * 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 * - * Licensed 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 * - * 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. + * 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.qpid.client.message; diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java new file mode 100644 index 0000000000..06081e6ebf --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java @@ -0,0 +1,292 @@ +/* + * + * 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.qpid.ping; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +import org.apache.qpid.requestreply.PingPongProducer; + +import uk.co.thebadgerset.junit.extensions.TimingController; +import uk.co.thebadgerset.junit.extensions.TimingControllerAware; + +import javax.jms.JMSException; +import javax.jms.Message; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +/** + * PingAsyncTestPerf is a performance test that outputs multiple timings from its test method, using the timing controller + * interface supplied by the test runner from a seperate listener thread. It differs from the {@link PingTestPerf} test + * that it extends because it can output timings as replies are received, rather than waiting until all expected replies + * are received. This is less 'blocky' than the tests in {@link PingTestPerf}, and provides a truer simulation of sending + * and recieving clients working asynchronously. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Send many ping messages and output timings asynchronously on batches received. + *
    + */ +public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerAware +{ + private static Logger _logger = Logger.getLogger(PingAsyncTestPerf.class); + + /** Holds the name of the property to get the test results logging batch size. */ + public static final String TEST_RESULTS_BATCH_SIZE_PROPNAME = "batchSize"; + + /** Holds the default test results logging batch size. */ + public static final int TEST_RESULTS_BATCH_SIZE_DEFAULT = 1000; + + /** Used to hold the timing controller passed from the test runner. */ + private TimingController _timingController; + + /** Used to generate unique correlation ids for each test run. */ + private AtomicLong corellationIdGenerator = new AtomicLong(); + + /** Holds test specifics by correlation id. This consists of the expected number of messages and the timing controler. */ + private Map perCorrelationIds = + Collections.synchronizedMap(new HashMap()); + + /** Holds the batched results listener, that does logging on batch boundaries. */ + private BatchedResultsListener batchedResultsListener = null; + + /** + * Creates a new asynchronous ping performance test with the specified name. + * + * @param name The test name. + */ + public PingAsyncTestPerf(String name) + { + super(name); + + // Sets up the test parameters with defaults. + testParameters.setPropertyIfNull(TEST_RESULTS_BATCH_SIZE_PROPNAME, + Integer.toString(TEST_RESULTS_BATCH_SIZE_DEFAULT)); + } + + /** + * Compile all the tests into a test suite. + * @return The test suite to run. Should only contain testAsyncPingOk method. + */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Ping Performance Tests"); + + // Run performance tests in read committed mode. + suite.addTest(new PingAsyncTestPerf("testAsyncPingOk")); + + return suite; + } + + /** + * Accepts a timing controller from the test runner. + * + * @param timingController The timing controller to register mutliple timings with. + */ + public void setTimingController(TimingController timingController) + { + _timingController = timingController; + } + + /** + * Gets the timing controller passed in by the test runner. + * + * @return The timing controller passed in by the test runner. + */ + public TimingController getTimingController() + { + return _timingController; + } + + /** + * Sends the specified number of pings, asynchronously outputs timings on every batch boundary, and waits until + * all replies have been received or a time out occurs before exiting this method. + * + * @param numPings The number of pings to send. + * @throws Exception pass all errors out to the test harness + */ + public void testAsyncPingOk(int numPings) throws Exception + { + // _logger.debug("public void testAsyncPingOk(int numPings): called"); + + // Ensure that at least one ping was requeusted. + if (numPings == 0) + { + _logger.error("Number of pings requested was zero."); + fail("Number of pings requested was zero."); + } + + // Get the per thread test setup to run the test through. + PerThreadSetup perThreadSetup = threadSetup.get(); + PingClient pingClient = perThreadSetup._pingClient; + + // Advance the correlation id of messages to send, to make it unique for this run. + perThreadSetup._correlationId = Long.toString(corellationIdGenerator.incrementAndGet()); + // String messageCorrelationId = perThreadSetup._correlationId; + // _logger.debug("messageCorrelationId = " + messageCorrelationId); + + // Initialize the count and timing controller for the new correlation id. + PerCorrelationId perCorrelationId = new PerCorrelationId(); + TimingController tc = getTimingController().getControllerForCurrentThread(); + perCorrelationId._tc = tc; + perCorrelationId._expectedCount = pingClient.getExpectedNumPings(numPings); + perCorrelationIds.put(perThreadSetup._correlationId, perCorrelationId); + + // Send the requested number of messages, and wait until they have all been received. + long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); + int numReplies = pingClient.pingAndWaitForReply(null, numPings, timeout, perThreadSetup._correlationId); + + // Check that all the replies were received and log a fail if they were not. + if (numReplies < perCorrelationId._expectedCount) + { + perCorrelationId._tc.completeTest(false, numPings - perCorrelationId._expectedCount); + } + + // Remove the expected count and timing controller for the message correlation id, to ensure they are cleaned up. + perCorrelationIds.remove(perThreadSetup._correlationId); + } + + /** + * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. + */ + public void threadSetUp() + { + _logger.debug("public void threadSetUp(): called"); + + try + { + // Call the set up method in the super class. This creates a PingClient pinger. + super.threadSetUp(); + + // Create the chained message listener, only if it has not already been created. This is set up with the + // batch size property, to tell it what batch size to output results on. A synchronized block is used to + // ensure that only one thread creates this. + synchronized (this) + { + if (batchedResultsListener == null) + { + int batchSize = Integer.parseInt(testParameters.getProperty(TEST_RESULTS_BATCH_SIZE_PROPNAME)); + batchedResultsListener = new BatchedResultsListener(batchSize); + } + } + + // Get the set up that the super class created. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Register the chained message listener on the pinger to do its asynchronous test timings from. + perThreadSetup._pingClient.setChainedMessageListener(batchedResultsListener); + } + catch (Exception e) + { + _logger.warn("There was an exception during per thread setup.", e); + } + } + + /** + * BatchedResultsListener is a {@link PingPongProducer.ChainedMessageListener} that can be attached to the + * pinger, in order to receive notifications about every message received and the number remaining to be + * received. Whenever the number remaining crosses a batch size boundary this results listener outputs + * a test timing for the actual number of messages received in the current batch. + */ + private class BatchedResultsListener implements PingPongProducer.ChainedMessageListener + { + /** The test results logging batch size. */ + int _batchSize; + + /** + * Creates a results listener on the specified batch size. + * + * @param batchSize The batch size to use. + */ + public BatchedResultsListener(int batchSize) + { + _batchSize = batchSize; + } + + /** + * This callback method is called from all of the pingers that this test creates. It uses the correlation id + * from the message to identify the timing controller for the test thread that was responsible for sending those + * messages. + * + * @param message The message. + * @param remainingCount The count of messages remaining to be received with a particular correlation id. + * + * @throws JMSException Any underlying JMSException is allowed to fall through. + */ + public void onMessage(Message message, int remainingCount, long latency) throws JMSException + { + // Check if a batch boundary has been crossed. + if ((remainingCount % _batchSize) == 0) + { + // Extract the correlation id from the message. + String correlationId = message.getJMSCorrelationID(); + + /*_logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount + + "): called on batch boundary for message id: " + correlationId + " with thread id: " + + Thread.currentThread().getId());*/ + + // Get the details for the correlation id and check that they are not null. They can become null + // if a test times out. + PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationId); + if (perCorrelationId != null) + { + // Get the timing controller and expected count for this correlation id. + TimingController tc = perCorrelationId._tc; + int expected = perCorrelationId._expectedCount; + + // Calculate how many messages were actually received in the last batch. This will be the batch size + // except where the number expected is not a multiple of the batch size and this is the first remaining + // count to cross a batch size boundary, in which case it will be the number expected modulo the batch + // size. + int receivedInBatch = ((expected - remainingCount) < _batchSize) ? (expected % _batchSize) : _batchSize; + + // Register a test result for the correlation id. + try + { + tc.completeTest(true, receivedInBatch); + } + catch (InterruptedException e) + { + // Ignore this. It means the test runner wants to stop as soon as possible. + _logger.warn("Got InterruptedException.", e); + } + } + // Else ignore, test timed out. Should log a fail here? + } + } + } + + /** + * Holds state specific to each correlation id, needed to output test results. This consists of the count of + * the total expected number of messages, and the timing controller for the thread sending those message ids. + */ + private static class PerCorrelationId + { + public int _expectedCount; + public TimingController _tc; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java index e3b0249ed3..ac12436951 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java @@ -20,12 +20,14 @@ */ package org.apache.qpid.ping; -import java.util.List; -import java.util.Properties; +import org.apache.log4j.Logger; + +import org.apache.qpid.requestreply.PingPongProducer; import javax.jms.Destination; -import org.apache.qpid.requestreply.PingPongProducer; +import java.util.List; +import java.util.Properties; /** * PingClient is a {@link PingPongProducer} that does not need a {@link org.apache.qpid.requestreply.PingPongBouncer} @@ -36,7 +38,7 @@ import org.apache.qpid.requestreply.PingPongProducer; * are created they will all be run in parallel and be active in sending and consuming pings at the same time. * If the unique destinations flag is not set and a pub/sub ping cycle is being run, this means that they will all hear * pings sent by each other. The expected number of pings received will therefore be multiplied up by the number of - * active ping clients. The {@link #getConsumersPerTopic()} method is used to supply this multiplier under these + * active ping clients. The {@link #getConsumersPerDestination()} method is used to supply this multiplier under these * conditions. * *

    @@ -47,6 +49,9 @@ import org.apache.qpid.requestreply.PingPongProducer; */ public class PingClient extends PingPongProducer { + /** Used for debugging. */ + private final Logger log = Logger.getLogger(PingClient.class); + /** Used to count the number of ping clients created. */ private static int _pingClientCount; @@ -82,15 +87,21 @@ public class PingClient extends PingPongProducer * * @return The scaling up of the number of expected pub/sub pings. */ - public int getConsumersPerTopic() + public int getConsumersPerDestination() { + log.debug("public int getConsumersPerDestination(): called"); + if (_isUnique) { - return 1; + log.debug("1 consumer per destination."); + + return _noOfConsumers; } else { - return _pingClientCount; + log.debug(_pingClientCount + " consumers per destination."); + + return _pingClientCount * _noOfConsumers; } } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java index 2765986868..db6f384914 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java @@ -20,18 +20,6 @@ */ package org.apache.qpid.ping; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.jms.Destination; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.jms.Message; - import org.apache.log4j.Logger; import org.apache.qpid.requestreply.PingPongProducer; @@ -40,6 +28,15 @@ import org.apache.qpid.util.CommandLineParser; import uk.co.thebadgerset.junit.extensions.util.MathUtils; import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; +import javax.jms.*; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; + /** * PingDurableClient is a variation of the {@link PingPongProducer} ping tool. Instead of sending its pings and * receiving replies to them at the same time, this tool sends pings until it is signalled by some 'event' to stop @@ -167,7 +164,8 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList try { // Create a ping producer overriding its defaults with all options passed on the command line. - Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); + Properties options = + CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); PingDurableClient pingProducer = new PingDurableClient(options); // Create a shutdown hook to terminate the ping-pong producer. @@ -219,7 +217,7 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList // Establish the connection and the message producer. establishConnection(true, false); - getConnection().start(); + _connection.start(); Message message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent); @@ -329,8 +327,8 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList _queueSharedID = new AtomicInteger(); establishConnection(false, true); - _consumer.setMessageListener(null); - _connection.start(); + _consumer[0].setMessageListener(null); + _consumerConnection[0].start(); // Try to receive all of the pings that were successfully sent. int messagesReceived = 0; @@ -339,7 +337,7 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList while (!endCondition) { // Message received = _consumer.receiveNoWait(); - Message received = _consumer.receive(TIME_OUT); + Message received = _consumer[0].receive(TIME_OUT); log.debug("received = " + received); if (received != null) @@ -362,11 +360,11 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList } // Ensure messages received are committed. - if (_transacted) + if (_consTransacted) { try { - _consumerSession.commit(); + _consumerSession[0].commit(); System.out.println("Committed for all messages received."); } catch (JMSException e) @@ -375,7 +373,7 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList System.out.println("Error during commit."); try { - _consumerSession.rollback(); + _consumerSession[0].rollback(); System.out.println("Rolled back on all messages received."); } catch (JMSException e2) diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java new file mode 100644 index 0000000000..55414664da --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java @@ -0,0 +1,314 @@ +/* + * + * 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.qpid.ping; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.message.AMQMessage; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.requestreply.PingPongProducer; + +import uk.co.thebadgerset.junit.extensions.TimingController; +import uk.co.thebadgerset.junit.extensions.TimingControllerAware; +import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.ObjectMessage; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +/** + * PingLatencyTestPerf is a performance test that outputs multiple timings from its test method, using the timing + * controller interface supplied by the test runner from a seperate listener thread. It outputs round trip timings for + * individual ping messages rather than for how long a complete batch of messages took to process. It also differs from + * the {@link PingTestPerf} test that it extends because it can output timings as replies are received, rather than + * waiting until all expected replies are received. + * + *

    This test does not output timings for every single ping message, as when running at high volume, writing the test + * log for a vast number of messages would slow the testing down. Instead samples ping latency occasionally. The + * frequency of ping sampling is set using the {@link #TEST_RESULTS_BATCH_SIZE_PROPNAME} property, to override the + * default of every {@link #DEFAULT_TEST_RESULTS_BATCH_SIZE}. + * + *

    The size parameter logged for each individual ping is set to the size of the batch of messages that the + * individual timed ping was taken from, rather than 1 for a single message. This is so that the total throughput + * (messages / time) can be calculated in order to examine the relationship between throughput and latency. + * + *

    CRC Card
    CRC Card
    Responsibilities Collaborations
    Send many ping + * messages and output timings for sampled individual pings.
    + */ +public class PingLatencyTestPerf extends PingTestPerf implements TimingControllerAware +{ + private static Logger _logger = Logger.getLogger(PingLatencyTestPerf.class); + + /** Holds the name of the property to get the test results logging batch size. */ + public static final String TEST_RESULTS_BATCH_SIZE_PROPNAME = "batchSize"; + + /** Holds the default test results logging batch size. */ + public static final int DEFAULT_TEST_RESULTS_BATCH_SIZE = 1000; + + /** Used to hold the timing controller passed from the test runner. */ + private TimingController _timingController; + + /** Used to generate unique correlation ids for each test run. */ + private AtomicLong corellationIdGenerator = new AtomicLong(); + + /** + * Holds test specifics by correlation id. This consists of the expected number of messages and the timing + * controler. + */ + private Map perCorrelationIds = + Collections.synchronizedMap(new HashMap()); + + /** Holds the batched results listener, that does logging on batch boundaries. */ + private BatchedResultsListener batchedResultsListener = null; + + /** + * Creates a new asynchronous ping performance test with the specified name. + * + * @param name The test name. + */ + public PingLatencyTestPerf(String name) + { + super(name); + + // Sets up the test parameters with defaults. + ParsedProperties.setSysPropertyIfNull(TEST_RESULTS_BATCH_SIZE_PROPNAME, + Integer.toString(DEFAULT_TEST_RESULTS_BATCH_SIZE)); + } + + /** Compile all the tests into a test suite. */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Ping Latency Tests"); + + // Run performance tests in read committed mode. + suite.addTest(new PingLatencyTestPerf("testPingLatency")); + + return suite; + } + + /** + * Accepts a timing controller from the test runner. + * + * @param timingController The timing controller to register mutliple timings with. + */ + public void setTimingController(TimingController timingController) + { + _timingController = timingController; + } + + /** + * Gets the timing controller passed in by the test runner. + * + * @return The timing controller passed in by the test runner. + */ + public TimingController getTimingController() + { + return _timingController; + } + + /** + * Sends the specified number of pings, asynchronously outputs timings on every batch boundary, and waits until all + * replies have been received or a time out occurs before exiting this method. + * + * @param numPings The number of pings to send. + */ + public void testPingLatency(int numPings) throws Exception + { + _logger.debug("public void testPingLatency(int numPings): called"); + + // Ensure that at least one ping was requeusted. + if (numPings == 0) + { + _logger.error("Number of pings requested was zero."); + } + + // Get the per thread test setup to run the test through. + PerThreadSetup perThreadSetup = threadSetup.get(); + PingClient pingClient = perThreadSetup._pingClient; + + // Advance the correlation id of messages to send, to make it unique for this run. + String messageCorrelationId = Long.toString(corellationIdGenerator.incrementAndGet()); + _logger.debug("messageCorrelationId = " + messageCorrelationId); + + // Initialize the count and timing controller for the new correlation id. + PerCorrelationId perCorrelationId = new PerCorrelationId(); + TimingController tc = getTimingController().getControllerForCurrentThread(); + perCorrelationId._tc = tc; + perCorrelationId._expectedCount = numPings; + perCorrelationIds.put(messageCorrelationId, perCorrelationId); + + // Attach the chained message listener to the ping producer to listen asynchronously for the replies to these + // messages. + pingClient.setChainedMessageListener(batchedResultsListener); + + // Generate a sample message of the specified size. + Message msg = + pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0), + testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), + testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); + + // Send the requested number of messages, and wait until they have all been received. + long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); + int numReplies = pingClient.pingAndWaitForReply(msg, numPings, timeout, null); + + // Check that all the replies were received and log a fail if they were not. + if (numReplies < numPings) + { + tc.completeTest(false, 0); + } + + // Remove the chained message listener from the ping producer. + pingClient.removeChainedMessageListener(); + + // Remove the expected count and timing controller for the message correlation id, to ensure they are cleaned up. + perCorrelationIds.remove(messageCorrelationId); + } + + /** Performs test fixture creation on a per thread basis. This will only be called once for each test thread. */ + public void threadSetUp() + { + _logger.debug("public void threadSetUp(): called"); + + try + { + // Call the set up method in the super class. This creates a PingClient pinger. + super.threadSetUp(); + + // Create the chained message listener, only if it has not already been created. This is set up with the + // batch size property, to tell it what batch size to output results on. A synchronized block is used to + // ensure that only one thread creates this. + synchronized (this) + { + if (batchedResultsListener == null) + { + int batchSize = Integer.parseInt(testParameters.getProperty(TEST_RESULTS_BATCH_SIZE_PROPNAME)); + batchedResultsListener = new BatchedResultsListener(batchSize); + } + } + + // Get the set up that the super class created. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Register the chained message listener on the pinger to do its asynchronous test timings from. + perThreadSetup._pingClient.setChainedMessageListener(batchedResultsListener); + } + catch (Exception e) + { + _logger.warn("There was an exception during per thread setup.", e); + } + } + + /** + * BatchedResultsListener is a {@link org.apache.qpid.requestreply.PingPongProducer.ChainedMessageListener} that can + * be attached to the pinger, in order to receive notifications about every message received and the number + * remaining to be received. Whenever the number remaining crosses a batch size boundary this results listener + * outputs a test timing for the actual number of messages received in the current batch. + */ + private class BatchedResultsListener implements PingPongProducer.ChainedMessageListener + { + /** The test results logging batch size. */ + int _batchSize; + private boolean _strictAMQP; + + /** + * Creates a results listener on the specified batch size. + * + * @param batchSize The batch size to use. + */ + public BatchedResultsListener(int batchSize) + { + _batchSize = batchSize; + _strictAMQP = + Boolean.parseBoolean(System.getProperties().getProperty(AMQSession.STRICT_AMQP, + AMQSession.STRICT_AMQP_DEFAULT)); + } + + /** + * This callback method is called from all of the pingers that this test creates. It uses the correlation id + * from the message to identify the timing controller for the test thread that was responsible for sending those + * messages. + * + * @param message The message. + * @param remainingCount The count of messages remaining to be received with a particular correlation id. + * + * @throws javax.jms.JMSException Any underlying JMSException is allowed to fall through. + */ + public void onMessage(Message message, int remainingCount, long latency) throws JMSException + { + _logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount + "): called"); + + // Check if a batch boundary has been crossed. + if ((remainingCount % _batchSize) == 0) + { + // Extract the correlation id from the message. + String correlationId = message.getJMSCorrelationID(); + + // Get the details for the correlation id and check that they are not null. They can become null + // if a test times out. + PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationId); + if (perCorrelationId != null) + { + // Get the timing controller and expected count for this correlation id. + TimingController tc = perCorrelationId._tc; + int expected = perCorrelationId._expectedCount; + + // Calculate how many messages were actually received in the last batch. This will be the batch size + // except where the number expected is not a multiple of the batch size and this is the first remaining + // count to cross a batch size boundary, in which case it will be the number expected modulo the batch + // size. + int receivedInBatch = ((expected - remainingCount) < _batchSize) ? (expected % _batchSize) : _batchSize; + + // Register a test result for the correlation id. + try + { + tc.completeTest(true, receivedInBatch, latency); + } + catch (InterruptedException e) + { + // Ignore this. It means the test runner wants to stop as soon as possible. + _logger.warn("Got InterruptedException.", e); + } + } + // Else ignore, test timed out. Should log a fail here? + } + } + } + + /** + * Holds state specific to each correlation id, needed to output test results. This consists of the count of the + * total expected number of messages, and the timing controller for the thread sending those message ids. + */ + private static class PerCorrelationId + { + public int _expectedCount; + public TimingController _tc; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java index bbe337ca0a..2879f0c322 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java @@ -57,7 +57,7 @@ public class PingSendOnlyClient extends PingDurableClient try { // Create a ping producer overriding its defaults with all options passed on the command line. - Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); PingSendOnlyClient pingProducer = new PingSendOnlyClient(options); // Create a shutdown hook to terminate the ping-pong producer. diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java new file mode 100644 index 0000000000..375007584b --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java @@ -0,0 +1,196 @@ +/* + * + * 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.qpid.ping; + +import junit.framework.Assert; +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +import org.apache.qpid.requestreply.PingPongProducer; + +import uk.co.thebadgerset.junit.extensions.AsymptoticTestCase; +import uk.co.thebadgerset.junit.extensions.TestThreadAware; +import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; +import uk.co.thebadgerset.junit.extensions.util.TestContextProperties; + +import javax.jms.*; + +/** + * PingTestPerf is a ping test, that has been written with the intention of being scaled up to run many times + * simultaneously to simluate many clients/producers/connections. + * + *

    A single run of the test using the default JUnit test runner will result in the sending and timing of a single + * full round trip ping. This test may be scaled up using a suitable JUnit test runner. + * + *

    The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a + * temporary queue for replies. This setup is only established once for all the test repeats/threads that may be run, + * except if the connection is lost in which case an attempt to re-establish the setup is made. + * + *

    The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that + * is the name of the temporary queue, fires off a message on the original queue and waits for a response on the + * temporary queue. + * + *

    Configurable test properties: message size, transacted or not, persistent or not. Broker connection details. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    + */ +public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware +{ + private static Logger _logger = Logger.getLogger(PingTestPerf.class); + + /** Thread local to hold the per-thread test setup fields. */ + ThreadLocal threadSetup = new ThreadLocal(); + + /** Holds a property reader to extract the test parameters from. */ + protected ParsedProperties testParameters = + TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/); + + public PingTestPerf(String name) + { + super(name); + + _logger.debug("testParameters = " + testParameters); + } + + /** + * Compile all the tests into a test suite. + * @return The test method testPingOk. + */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Ping Performance Tests"); + + // Run performance tests in read committed mode. + suite.addTest(new PingTestPerf("testPingOk")); + + return suite; + } + + public void testPingOk(int numPings) throws Exception + { + if (numPings == 0) + { + Assert.fail("Number of pings requested was zero."); + } + + // Get the per thread test setup to run the test through. + PerThreadSetup perThreadSetup = threadSetup.get(); + + if (perThreadSetup == null) + { + Assert.fail("Could not get per thread test setup, it was null."); + } + + // Generate a sample message. This message is already time stamped and has its reply-to destination set. + Message msg = + perThreadSetup._pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0), + testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), + testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); + + // start the test + long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); + int numReplies = perThreadSetup._pingClient.pingAndWaitForReply(msg, numPings, timeout, null); + + // Fail the test if the timeout was exceeded. + if (numReplies != perThreadSetup._pingClient.getExpectedNumPings(numPings)) + { + Assert.fail("The ping timed out after " + timeout + " ms. Messages Sent = " + numPings + ", MessagesReceived = " + + numReplies); + } + } + + /** + * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. + */ + public void threadSetUp() + { + _logger.debug("public void threadSetUp(): called"); + + try + { + PerThreadSetup perThreadSetup = new PerThreadSetup(); + + // This is synchronized because there is a race condition, which causes one connection to sleep if + // all threads try to create connection concurrently. + synchronized (this) + { + // Establish a client to ping a Destination and listen the reply back from same Destination + perThreadSetup._pingClient = new PingClient(testParameters); + perThreadSetup._pingClient.establishConnection(true, true); + } + // Start the client connection + perThreadSetup._pingClient.start(); + + // Attach the per-thread set to the thread. + threadSetup.set(perThreadSetup); + } + catch (Exception e) + { + _logger.warn("There was an exception during per thread setup.", e); + } + } + + /** + * Performs test fixture clean + */ + public void threadTearDown() + { + _logger.debug("public void threadTearDown(): called"); + + try + { + // Get the per thread test fixture. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Close the pingers so that it cleans up its connection cleanly. + synchronized (this) + { + if ((perThreadSetup != null) && (perThreadSetup._pingClient != null)) + { + perThreadSetup._pingClient.close(); + } + } + } + catch (JMSException e) + { + _logger.warn("There was an exception during per thread tear down."); + } + finally + { + // Ensure the per thread fixture is reclaimed. + threadSetup.remove(); + } + } + + protected static class PerThreadSetup + { + /** + * Holds the test ping client. + */ + protected PingClient _pingClient; + protected String _correlationId; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java index 78ab7c4c73..82b36bf233 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -92,10 +92,10 @@ public class PingPongBouncer implements MessageListener /** The producer for sending replies with. */ private MessageProducer _replyProducer; - /** The consumer session. */ + /** The consumer controlSession. */ private Session _consumerSession; - /** The producer session. */ + /** The producer controlSession. */ private Session _producerSession; /** Holds the connection to the broker. */ @@ -149,7 +149,7 @@ public class PingPongBouncer implements MessageListener // Set up the failover notifier. getConnection().setConnectionListener(new FailoverNotifier()); - // Create a session to listen for messages on and one to send replies on, transactional depending on the + // Create a controlSession to listen for messages on and one to send replies on, transactional depending on the // command line option. _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); @@ -323,8 +323,8 @@ public class PingPongBouncer implements MessageListener } /** - * Convenience method to commit the transaction on the specified session. If the session to commit on is not - * a transactional session, this method does nothing. + * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not + * a transactional controlSession, this method does nothing. * *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index d5d1c304e9..bd34fd8f20 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -20,21 +20,8 @@ */ package org.apache.qpid.requestreply; -import java.io.IOException; -import java.net.InetAddress; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import javax.jms.*; - import org.apache.log4j.Logger; +import org.apache.log4j.NDC; import org.apache.qpid.AMQException; import org.apache.qpid.client.*; @@ -51,6 +38,18 @@ import uk.co.thebadgerset.junit.extensions.BatchedThrottle; import uk.co.thebadgerset.junit.extensions.Throttle; import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; +import javax.jms.*; + +import java.io.IOException; +import java.net.InetAddress; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + /** * PingPongProducer is a client that sends test messages, and waits for replies to these messages. The replies may * either be generated by another client (see {@link PingPongBouncer}, or an extension of it may be used that listens @@ -86,10 +85,11 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; *

    username guest The username to access the broker with. *
    password guest The password to access the broker with. *
    selector null Not used. Defines a message selector to filter pings with. - *
    destinationCount 1 The number of receivers listening to the pings. + *
    destinationCount 1 The number of destinations to send pings to. + *
    numConsumers 1 The number of consumers on each destination. *
    timeout 30000 In milliseconds. The timeout to stop waiting for replies. *
    commitBatchSize 1 The number of messages per transaction in transactional mode. - *
    uniqueDests true Whether each receiver only listens to one ping destination or all. + *
    uniqueDests true Whether each receivers only listens to one ping destination or all. *
    durableDests false Whether or not durable destinations are used. *
    ackMode AUTO_ACK The message acknowledgement mode. Possible values are: * 0 - SESSION_TRANSACTED @@ -98,6 +98,10 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; * 3 - DUPS_OK_ACKNOWLEDGE * 257 - NO_ACKNOWLEDGE * 258 - PRE_ACKNOWLEDGE + *
    consTransacted false Whether or not consumers use transactions. Defaults to the same value + * as the 'transacted' option if not seperately defined. + *
    consAckMode AUTO_ACK The message acknowledgement mode for consumers. Defaults to the same + * value as 'ackMode' if not seperately defined. *
    maxPending 0 The maximum size in bytes, of messages sent but not yet received. * Limits the volume of messages currently buffered on the client * or broker. Can help scale test clients by limiting amount of buffered @@ -131,8 +135,9 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; * Instead make mina use a bounded blocking buffer, or other form of back pressure, to stop data being written * faster than it can be sent. */ -public class PingPongProducer implements Runnable, MessageListener, ExceptionListener +public class PingPongProducer implements Runnable /*, MessageListener*/, ExceptionListener { + /** Used for debugging. */ private static final Logger log = Logger.getLogger(PingPongProducer.class); /** Holds the name of the property to get the test message size from. */ @@ -159,6 +164,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Holds the transactional mode to use for the test. */ public static final boolean TRANSACTED_DEFAULT = false; + public static final String CONSUMER_TRANSACTED_PROPNAME = "consTransacted"; + public static final boolean CONSUMER_TRANSACTED_DEFAULT = false; + /** Holds the name of the property to get the test broker url from. */ public static final String BROKER_PROPNAME = "broker"; @@ -237,12 +245,18 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Holds the default message selector. */ public static final String SELECTOR_DEFAULT = ""; - /** Holds the name of the proeprty to get the destination count from. */ + /** Holds the name of the property to get the destination count from. */ public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; /** Defines the default number of destinations to ping. */ public static final int DESTINATION_COUNT_DEFAULT = 1; + /** Holds the name of the property to get the number of consumers per destination from. */ + public static final String NUM_CONSUMERS_PROPNAME = "numConsumers"; + + /** Defines the default number consumers per destination. */ + public static final int NUM_CONSUMERS_DEFAULT = 1; + /** Holds the name of the property to get the waiting timeout for response messages. */ public static final String TIMEOUT_PROPNAME = "timeout"; @@ -270,6 +284,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Defines the default message acknowledgement mode. */ public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; + public static final String CONSUMER_ACK_MODE_PROPNAME = "consAckMode"; + public static final int CONSUMER_ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; + public static final String MAX_PENDING_PROPNAME = "maxPending"; public static final int MAX_PENDING_DEFAULT = 0; @@ -297,8 +314,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis defaults.setPropertyIfNull(PING_QUEUE_NAME_PROPNAME, PING_QUEUE_NAME_DEFAULT); defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT); defaults.setPropertyIfNull(TRANSACTED_PROPNAME, TRANSACTED_DEFAULT); + defaults.setPropertyIfNull(CONSUMER_TRANSACTED_PROPNAME, CONSUMER_TRANSACTED_DEFAULT); defaults.setPropertyIfNull(PERSISTENT_MODE_PROPNAME, PERSISTENT_MODE_DEFAULT); defaults.setPropertyIfNull(ACK_MODE_PROPNAME, ACK_MODE_DEFAULT); + defaults.setPropertyIfNull(CONSUMER_ACK_MODE_PROPNAME, CONSUMER_ACK_MODE_DEFAULT); defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT); defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT); defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT); @@ -311,6 +330,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis defaults.setPropertyIfNull(FAIL_ONCE_PROPNAME, FAIL_ONCE_DEFAULT); defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT); defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT); + defaults.setPropertyIfNull(NUM_CONSUMERS_PROPNAME, NUM_CONSUMERS_DEFAULT); defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT); defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT); defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT); @@ -323,12 +343,15 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis protected String _destinationName; protected String _selector; protected boolean _transacted; + protected boolean _consTransacted; /** Determines whether this producer sends persistent messages. */ protected boolean _persistent; /** Holds the acknowledgement mode used for sending and receiving messages. */ - private int _ackMode; + protected int _ackMode; + + protected int _consAckMode; /** Determines what size of messages this producer sends. */ protected int _messageSize; @@ -363,7 +386,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Holds the number of sends that should be performed in every transaction when using transactions. */ protected int _txBatchSize; + /** Holds the number of destinations to ping. */ protected int _noOfDestinations; + + /** Holds the number of consumers per destination. */ + protected int _noOfConsumers; + + /** Holds the maximum send rate in herz. */ protected int _rate; /** @@ -373,7 +402,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis protected int _maxPendingSize; /** - * Holds a monitor which is used to synchronize sender and receiver threads, where the sender has elected + * Holds a monitor which is used to synchronize sender and receivers threads, where the sender has elected * to wait until the number of unreceived message is reduced before continuing to send. */ protected Object _sendPauseMonitor = new Object(); @@ -397,10 +426,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis /** Holds the connection to the broker. */ protected Connection _connection; - /** Holds the session on which ping replies are received. */ - protected Session _consumerSession; + /** Holds the consumer connections. */ + protected Connection[] _consumerConnection; - /** Holds the producer session, needed to create ping messages. */ + /** Holds the controlSession on which ping replies are received. */ + protected Session[] _consumerSession; + + /** Holds the producer controlSession, needed to create ping messages. */ protected Session _producerSession; /** Holds the destination where the response messages will arrive. */ @@ -434,18 +466,15 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis protected MessageProducer _producer; /** Holds the message consumer to receive the ping replies through. */ - protected MessageConsumer _consumer; - - /** - * Holds the number of consumers that will be attached to each topic. Each pings will result in a reply from each of the - * attached clients - */ - static int _consumersPerTopic = 1; + protected MessageConsumer[] _consumer; /** The prompt to display when asking the user to kill the broker for failover testing. */ private static final String KILL_BROKER_PROMPT = "Kill broker now, then press Return."; private String _clientID; + /** Keeps count of the total messages sent purely for debugging purposes. */ + private static AtomicInteger numSent = new AtomicInteger(); + /** * Creates a ping producer with the specified parameters, of which there are many. See the class level comments * for details. This constructor creates a connection to the broker and creates producer and consumer sessions on @@ -457,7 +486,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public PingPongProducer(Properties overrides) throws Exception { - log.debug("public PingPongProducer(Properties overrides = " + overrides + "): called"); + // log.debug("public PingPongProducer(Properties overrides = " + overrides + "): called"); // Create a set of parsed properties from the defaults overriden by the passed in values. ParsedProperties properties = new ParsedProperties(defaults); @@ -471,6 +500,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _destinationName = properties.getProperty(PING_QUEUE_NAME_PROPNAME); _selector = properties.getProperty(SELECTOR_PROPNAME); _transacted = properties.getPropertyAsBoolean(TRANSACTED_PROPNAME); + _consTransacted = properties.getPropertyAsBoolean(CONSUMER_TRANSACTED_PROPNAME); _persistent = properties.getPropertyAsBoolean(PERSISTENT_MODE_PROPNAME); _messageSize = properties.getPropertyAsInteger(MESSAGE_SIZE_PROPNAME); _verbose = properties.getPropertyAsBoolean(VERBOSE_PROPNAME); @@ -481,11 +511,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _failOnce = properties.getPropertyAsBoolean(FAIL_ONCE_PROPNAME); _txBatchSize = properties.getPropertyAsInteger(TX_BATCH_SIZE_PROPNAME); _noOfDestinations = properties.getPropertyAsInteger(DESTINATION_COUNT_PROPNAME); + _noOfConsumers = properties.getPropertyAsInteger(NUM_CONSUMERS_PROPNAME); _rate = properties.getPropertyAsInteger(RATE_PROPNAME); _isPubSub = properties.getPropertyAsBoolean(PUBSUB_PROPNAME); _isUnique = properties.getPropertyAsBoolean(UNIQUE_DESTS_PROPNAME); _isDurable = properties.getPropertyAsBoolean(DURABLE_DESTS_PROPNAME); _ackMode = properties.getPropertyAsInteger(ACK_MODE_PROPNAME); + _consAckMode = properties.getPropertyAsInteger(CONSUMER_ACK_MODE_PROPNAME); _maxPendingSize = properties.getPropertyAsInteger(MAX_PENDING_PROPNAME); // Check that one or more destinations were specified. @@ -516,7 +548,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public void establishConnection(boolean producer, boolean consumer) throws Exception { - log.debug("public void establishConnection(): called"); + // log.debug("public void establishConnection(): called"); // Generate a unique identifying name for this client, based on it ip address and the current time. InetAddress address = InetAddress.getLocalHost(); @@ -526,11 +558,17 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis createConnection(_clientID); // Create transactional or non-transactional sessions, based on the command line arguments. - _producerSession = (Session) getConnection().createSession(_transacted, _ackMode); - _consumerSession = (Session) getConnection().createSession(_transacted, _ackMode); + _producerSession = (Session) _connection.createSession(_transacted, _ackMode); + + _consumerSession = new Session[_noOfConsumers]; + + for (int i = 0; i < _noOfConsumers; i++) + { + _consumerSession[i] = (Session) _consumerConnection[i].createSession(_consTransacted, _consAckMode); + } // Create the destinations to send pings to and receive replies from. - _replyDestination = _consumerSession.createTemporaryQueue(); + _replyDestination = _consumerSession[0].createTemporaryQueue(); createPingDestinations(_noOfDestinations, _selector, _destinationName, _isUnique, _isDurable); // Create the message producer only if instructed to. @@ -557,7 +595,20 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ protected void createConnection(String clientID) throws AMQException, URLSyntaxException { + // log.debug("protected void createConnection(String clientID = " + clientID + "): called"); + + // log.debug("Creating a connection for the message producer."); + _connection = new AMQConnection(_brokerDetails, _username, _password, clientID, _virtualpath); + + // log.debug("Creating " + _noOfConsumers + " connections for the consumers."); + + _consumerConnection = new Connection[_noOfConsumers]; + + for (int i = 0; i < _noOfConsumers; i++) + { + _consumerConnection[i] = new AMQConnection(_brokerDetails, _username, _password, clientID, _virtualpath); + } } /** @@ -570,20 +621,21 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { try { - Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {})); + Properties options = + CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); // Create a ping producer overriding its defaults with all options passed on the command line. PingPongProducer pingProducer = new PingPongProducer(options); pingProducer.establishConnection(true, true); // Start the ping producers dispatch thread running. - pingProducer.getConnection().start(); + pingProducer._connection.start(); // Create a shutdown hook to terminate the ping-pong producer. Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. - pingProducer.getConnection().setExceptionListener(pingProducer); + pingProducer._connection.setExceptionListener(pingProducer); // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. Thread pingThread = new Thread(pingProducer); @@ -624,12 +676,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public List getReplyDestinations() { - log.debug("public List getReplyDestinations(): called"); + // log.debug("public List getReplyDestinations(): called"); List replyDestinations = new ArrayList(); replyDestinations.add(_replyDestination); - log.debug("replyDestinations = " + replyDestinations); + // log.debug("replyDestinations = " + replyDestinations); return replyDestinations; } @@ -642,12 +694,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public void createProducer() throws JMSException { - log.debug("public void createProducer(): called"); + // log.debug("public void createProducer(): called"); _producer = (MessageProducer) _producerSession.createProducer(null); _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - log.debug("Created producer for " + (_persistent ? "persistent" : "non-persistent") + " messages."); + // log.debug("Created producer for " + (_persistent ? "persistent" : "non-persistent") + " messages."); } /** @@ -665,14 +717,14 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique, boolean durable) throws JMSException, AMQException { - log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " + /*log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = " - + durable + "): called"); + + durable + "): called");*/ _pingDestinations = new ArrayList(); // Create the desired number of ping destinations and consumers for them. - log.debug("Creating " + noOfDestinations + " destinations to ping."); + // log.debug("Creating " + noOfDestinations + " destinations to ping."); for (int i = 0; i < noOfDestinations; i++) { @@ -683,12 +735,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag. if (unique) { - log.debug("Creating unique destinations."); + // log.debug("Creating unique destinations."); id = "_" + _queueJVMSequenceID.incrementAndGet() + "_" + _connection.getClientID(); } else { - log.debug("Creating shared destinations."); + // log.debug("Creating shared destinations."); id = "_" + _queueSharedID.incrementAndGet(); } @@ -698,14 +750,14 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis if (!durable) { destination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id); - log.debug("Created non-durable topic " + destination); + // log.debug("Created non-durable topic " + destination); } else { destination = AMQTopic.createDurableTopic(new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id), _clientID, (AMQConnection) _connection); - log.debug("Created durable topic " + destination); + // log.debug("Created durable topic " + destination); } } // Otherwise this is a p2p pinger, in which case create queues. @@ -719,7 +771,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis ((AMQSession) _producerSession).bindQueue(destinationName, destinationName, null, ExchangeDefaults.DIRECT_EXCHANGE_NAME); - log.debug("Created queue " + destination); + // log.debug("Created queue " + destination); } // Keep the destination. @@ -737,20 +789,36 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public void createReplyConsumers(Collection destinations, String selector) throws JMSException { - log.debug("public void createReplyConsumers(Collection destinations = " + destinations - + ", String selector = " + selector + "): called"); + /*log.debug("public void createReplyConsumers(Collection destinations = " + destinations + + ", String selector = " + selector + "): called");*/ - log.debug("Creating " + destinations.size() + " reply consumers."); + // log.debug("There are " + destinations.size() + " destinations."); + // log.debug("Creating " + _noOfConsumers + " consumers on each destination."); + // log.debug("Total number of consumers is: " + (destinations.size() * _noOfConsumers)); for (Destination destination : destinations) { - // Create a consumer for the destination and set this pinger to listen to its messages. - _consumer = - _consumerSession.createConsumer(destination, PREFETCH_DEFAULT, NO_LOCAL_DEFAULT, EXCLUSIVE_DEFAULT, - selector); - _consumer.setMessageListener(this); + _consumer = new MessageConsumer[_noOfConsumers]; + + for (int i = 0; i < _noOfConsumers; i++) + { + // Create a consumer for the destination and set this pinger to listen to its messages. + _consumer[i] = + _consumerSession[i].createConsumer(destination, PREFETCH_DEFAULT, NO_LOCAL_DEFAULT, EXCLUSIVE_DEFAULT, + selector); + + final int consumerNo = i; - log.debug("Set this to listen to replies sent to destination: " + destination); + _consumer[i].setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + onMessageWithConsumerNo(message, consumerNo); + } + }); + + // log.debug("Set consumer " + i + " to listen to replies sent to destination: " + destination); + } } } @@ -761,97 +829,123 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * * @param message The received message. */ - public void onMessage(Message message) + public void onMessageWithConsumerNo(Message message, int consumerNo) { - // log.debug("public void onMessage(Message message): called"); - + // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo = " + consumerNo + "): called"); try { + long now = System.nanoTime(); + long timestamp = getTimestamp(message); + long pingTime = now - timestamp; + + // NDC.push("cons" + consumerNo); + // Extract the messages correlation id. String correlationID = message.getJMSCorrelationID(); // log.debug("correlationID = " + correlationID); - // Countdown on the traffic light if there is one for the matching correlation id. - PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); + int num = message.getIntProperty("MSG_NUM"); + // log.info("Message " + num + " received."); + + boolean isRedelivered = message.getJMSRedelivered(); + // log.debug("isRedelivered = " + isRedelivered); - if (perCorrelationId != null) + if (!isRedelivered) { - CountDownLatch trafficLight = perCorrelationId.trafficLight; + // Countdown on the traffic light if there is one for the matching correlation id. + PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); - // Restart the timeout timer on every message. - perCorrelationId.timeOutStart = System.nanoTime(); + if (perCorrelationId != null) + { + CountDownLatch trafficLight = perCorrelationId.trafficLight; - // log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); + // Restart the timeout timer on every message. + perCorrelationId.timeOutStart = System.nanoTime(); - // Decrement the countdown latch. Before this point, it is possible that two threads might enter this - // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block - // ensures that each thread will get a unique value for the remaining messages. - long trueCount = -1; - long remainingCount = -1; + // log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); - synchronized (trafficLight) - { - trafficLight.countDown(); + // Decrement the countdown latch. Before this point, it is possible that two threads might enter this + // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block + // ensures that each thread will get a unique value for the remaining messages. + long trueCount = -1; + long remainingCount = -1; - trueCount = trafficLight.getCount(); - remainingCount = trueCount - 1; + synchronized (trafficLight) + { + trafficLight.countDown(); - // Decrement the count of sent but not yet received messages. - int unreceived = _unreceived.decrementAndGet(); - int unreceivedSize = (unreceived * ((_messageSize == 0) ? 1 : _messageSize)); + trueCount = trafficLight.getCount(); + remainingCount = trueCount - 1; - // Release a waiting sender if there is one. - synchronized (_sendPauseMonitor) - { - if ((_maxPendingSize > 0) && (unreceivedSize < _maxPendingSize)) - // && (_sendPauseBarrier.getNumberWaiting() == 1)) + // Decrement the count of sent but not yet received messages. + int unreceived = _unreceived.decrementAndGet(); + int unreceivedSize = (unreceived * ((_messageSize == 0) ? 1 : _messageSize)); + + // Release a waiting sender if there is one. + synchronized (_sendPauseMonitor) { - log.debug("unreceived size estimate under limit = " + unreceivedSize); - - // Wait on the send pause barrier for the limit to be re-established. - /*try - {*/ - // _sendPauseBarrier.await(); - _sendPauseMonitor.notify(); - /*} - catch (InterruptedException e) + if ((_maxPendingSize > 0) && (unreceivedSize < _maxPendingSize)) + // && (_sendPauseBarrier.getNumberWaiting() == 1)) { - throw new RuntimeException(e); + // log.debug("unreceived size estimate under limit = " + unreceivedSize); + + // Wait on the send pause barrier for the limit to be re-established. + /*try + {*/ + // _sendPauseBarrier.await(); + _sendPauseMonitor.notify(); + /*} + catch (InterruptedException e) + { + throw new RuntimeException(e); + } + catch (BrokenBarrierException e) + { + throw new RuntimeException(e); + }*/ } - catch (BrokenBarrierException e) - { - throw new RuntimeException(e); - }*/ } - } - // log.debug("remainingCount = " + remainingCount); - // log.debug("trueCount = " + trueCount); + // NDC.push("/rem" + remainingCount); - // Commit on transaction batch size boundaries. At this point in time the waiting producer remains - // blocked, even on the last message. - if ((remainingCount % _txBatchSize) == 0) - { - commitTx(_consumerSession); - } + // log.debug("remainingCount = " + remainingCount); + // log.debug("trueCount = " + trueCount); - // Forward the message and remaining count to any interested chained message listener. - if (_chainedMessageListener != null) - { - _chainedMessageListener.onMessage(message, (int) remainingCount); - } + // Commit on transaction batch size boundaries. At this point in time the waiting producer remains + // blocked, even on the last message. + // Commit count is divided by noOfConsumers in p2p mode, so that each consumer only commits on + // each batch boundary. For pub/sub each consumer gets every message so no division is done. + long commitCount = _isPubSub ? remainingCount : (remainingCount / _noOfConsumers); + // log.debug("commitCount = " + commitCount); - // Check if this is the last message, in which case release any waiting producers. This is done - // after the transaction has been committed and any listeners notified. - if (trueCount == 1) - { - trafficLight.countDown(); + if ((commitCount % _txBatchSize) == 0) + { + // log.debug("Trying commit for consumer " + consumerNo + "."); + commitTx(_consumerSession[consumerNo]); + } + + // Forward the message and remaining count to any interested chained message listener. + if (_chainedMessageListener != null) + { + _chainedMessageListener.onMessage(message, (int) remainingCount, pingTime); + } + + // Check if this is the last message, in which case release any waiting producers. This is done + // after the transaction has been committed and any listeners notified. + if (trueCount == 1) + { + trafficLight.countDown(); + } } } + else + { + log.warn("Got unexpected message with correlationId: " + correlationID); + } } else { - log.warn("Got unexpected message with correlationId: " + correlationID); + log.warn("Got redelivered message, ignoring."); } // Print out ping times for every message in verbose mode only. @@ -870,8 +964,11 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { log.warn("There was a JMSException: " + e.getMessage(), e); } - - // log.debug("public void onMessage(Message message): ending"); + finally + { + // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo): ending"); + // NDC.clear(); + } } /** @@ -893,8 +990,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) throws JMSException, InterruptedException { - log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " - + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called"); + /*log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ // Generate a unique correlation id to put on the messages before sending them, if one was not specified. if (messageCorrelationId == null) @@ -904,6 +1001,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis try { + // NDC.push("prod"); + // Create a count down latch to count the number of replies with. This is created before the messages are // sent so that the replies cannot be received before the count down is created. // One is added to this, so that the last reply becomes a special case. The special case is that the @@ -935,16 +1034,16 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis allMessagesReceived = numReplies == getExpectedNumPings(numPings); - log.debug("numReplies = " + numReplies); - log.debug("allMessagesReceived = " + allMessagesReceived); + // log.debug("numReplies = " + numReplies); + // log.debug("allMessagesReceived = " + allMessagesReceived); // Recheck the timeout condition. long now = System.nanoTime(); long lastMessageReceievedAt = perCorrelationId.timeOutStart; timedOut = (now - lastMessageReceievedAt) > (timeout * 1000000); - log.debug("now = " + now); - log.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); + // log.debug("now = " + now); + // log.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); } while (!timedOut && !allMessagesReceived); @@ -957,9 +1056,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis log.info("Got all replies on id, " + messageCorrelationId); } - commitTx(_consumerSession); + // commitTx(_consumerSession); - log.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); + // log.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); return numReplies; } @@ -967,6 +1066,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // so will be a memory leak if this is not done. finally { + // NDC.pop(); perCorrelationIds.remove(messageCorrelationId); } } @@ -982,8 +1082,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException { - log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings - + ", String messageCorrelationId = " + messageCorrelationId + "): called"); + /*log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings + + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ if (message == null) { @@ -1067,7 +1167,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis if (unreceivedSize > _maxPendingSize) { - log.debug("unreceived size estimate over limit = " + unreceivedSize); + // log.debug("unreceived size estimate over limit = " + unreceivedSize); // Wait on the send pause barrier for the limit to be re-established. try @@ -1096,11 +1196,19 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Send the message either to its round robin destination, or its default destination. if (destination == null) { + int num = numSent.incrementAndGet(); + message.setIntProperty("MSG_NUM", num); + setTimestamp(message); _producer.send(message); + // log.info("Message " + num + " sent."); } else { + int num = numSent.incrementAndGet(); + message.setIntProperty("MSG_NUM", num); + setTimestamp(message); _producer.send(destination, message); + // log.info("Message " + num + " sent."); } // Increase the unreceived size, this may actually happen aftern the message is recevied. @@ -1118,6 +1226,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Commit on every transaction batch size boundary. Here i + 1 is the count of actual messages sent. if (((i + 1) % _txBatchSize) == 0) { + // log.debug("Trying commit on producer session."); committed = commitTx(_producerSession); } @@ -1135,7 +1244,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis { // Generate a sample message and time stamp it. Message msg = getTestMessage(_replyDestination, _messageSize, _persistent); - setTimestamp(msg); + // setTimestamp(msg); // Send the message and wait for a reply. pingAndWaitForReply(msg, TX_BATCH_SIZE_DEFAULT, TIMEOUT_DEFAULT, null); @@ -1143,12 +1252,12 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis catch (JMSException e) { _publish = false; - log.debug("There was a JMSException: " + e.getMessage(), e); + // log.debug("There was a JMSException: " + e.getMessage(), e); } catch (InterruptedException e) { _publish = false; - log.debug("There was an interruption: " + e.getMessage(), e); + // log.debug("There was an interruption: " + e.getMessage(), e); } } @@ -1186,7 +1295,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Timestamp the message in nanoseconds. - setTimestamp(msg); + // setTimestamp(msg); return msg; } @@ -1227,6 +1336,16 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _publish = false; } + public void start() throws JMSException + { + _connection.start(); + + for (int i = 0; i < _noOfConsumers; i++) + { + _consumerConnection[i].start(); + } + } + /** Implements a ping loop that repeatedly pings until the publish flag becomes false. */ public void run() { @@ -1245,7 +1364,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public void onException(JMSException e) { - log.debug("public void onException(JMSException e = " + e + "): called", e); + // log.debug("public void onException(JMSException e = " + e + "): called", e); _publish = false; } @@ -1266,16 +1385,6 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis }); } - /** - * Gets the underlying connection that this ping client is running on. - * - * @return The underlying connection that this ping client is running on. - */ - public Connection getConnection() - { - return _connection; - } - /** * Closes the pingers connection. * @@ -1283,14 +1392,23 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public void close() throws JMSException { - log.debug("public void close(): called"); + // log.debug("public void close(): called"); try { if (_connection != null) { _connection.close(); - log.debug("Close connection."); + // log.debug("Close connection."); + } + + for (int i = 0; i < _noOfConsumers; i++) + { + if (_consumerConnection[i] != null) + { + _consumerConnection[i].close(); + // log.debug("Closed consumer connection."); + } } } finally @@ -1298,6 +1416,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _connection = null; _producerSession = null; _consumerSession = null; + _consumerConnection = null; _producer = null; _consumer = null; _pingDestinations = null; @@ -1306,8 +1425,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * Convenience method to commit the transaction on the specified session. If the session to commit on is not a - * transactional session, this method does nothing (unless the failover after send flag is set). + * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not a + * transactional controlSession, this method does nothing (unless the failover after send flag is set). * *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit is * applied. This flag applies whether the pinger is transactional or not. @@ -1316,9 +1435,9 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis * is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker after the * commit is applied. These flags will only apply if using a transactional pinger. * - * @param session The session to commit + * @param session The controlSession to commit * - * @return true if the session was committed, false if it was not. + * @return true if the controlSession was committed, false if it was not. * * @throws javax.jms.JMSException If the commit fails and then the rollback fails. * @@ -1347,6 +1466,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis if (session.getTransacted()) { + // log.debug("Session is transacted."); + try { if (_failBeforeCommit) @@ -1360,10 +1481,10 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis waitForUser(KILL_BROKER_PROMPT); } - // long l = System.nanoTime(); + long start = System.nanoTime(); session.commit(); committed = true; - // log.debug("Time taken to commit :" + ((System.nanoTime() - l) / 1000000f) + " ms"); + // log.debug("Time taken to commit :" + ((System.nanoTime() - start) / 1000000f) + " ms"); if (_failAfterCommit) { @@ -1376,26 +1497,26 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis waitForUser(KILL_BROKER_PROMPT); } - // log.trace("Session Commited."); + // log.debug("Session Commited."); } catch (JMSException e) { - log.debug("JMSException on commit:" + e.getMessage(), e); + // log.debug("JMSException on commit:" + e.getMessage(), e); // Warn that the bounce back client is not available. if (e.getLinkedException() instanceof AMQNoConsumersException) { - log.debug("No consumers on queue."); + // log.debug("No consumers on queue."); } try { session.rollback(); - log.debug("Message rolled back."); + // log.debug("Message rolled back."); } catch (JMSException jmse) { - log.debug("JMSE on rollback:" + jmse.getMessage(), jmse); + // log.debug("JMSE on rollback:" + jmse.getMessage(), jmse); // Both commit and rollback failed. Throw the rollback exception. throw jmse; @@ -1428,23 +1549,34 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis } /** - * This value will be changed by PingClient to represent the number of clients connected to each topic. + * Gets the number of consumers that are listening to each destination in the test. * * @return int The number of consumers subscribing to each topic. */ - public int getConsumersPerTopic() + public int getConsumersPerDestination() { - return _consumersPerTopic; + return _noOfConsumers; } + /** + * Calculates how many pings are expected to be received for the given number sent. + * + * @param numpings The number of pings that will be sent. + * + * @return The number that should be received, for the test to pass. + */ public int getExpectedNumPings(int numpings) { - return numpings * getConsumersPerTopic(); + // log.debug("public int getExpectedNumPings(int numpings = " + numpings + "): called"); + + // log.debug("Each ping will be received by " + (_isPubSub ? getConsumersPerDestination() : 1) + " consumers."); + + return numpings * (_isPubSub ? getConsumersPerDestination() : 1); } /** * Defines a chained message listener interface that can be attached to this pinger. Whenever this pinger's {@link - * PingPongProducer#onMessage} method is called, the chained listener set through the {@link + * PingPongProducer#onMessageWithConsumerNo} method is called, the chained listener set through the {@link * PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected count of * messages with that correlation id. * @@ -1454,7 +1586,17 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */ public static interface ChainedMessageListener { - public void onMessage(Message message, int remainingCount) throws JMSException; + /** + * Notifies interested listeners about message arrival and important test stats, the number of messages + * remaining in the test, and the messages send timestamp. + * + * @param message The newly arrived message. + * @param remainingCount The number of messages left to complete the test. + * @param latency The nanosecond latency of the message. + * + * @throws JMSException Any JMS exceptions is allowed to fall through. + */ + public void onMessage(Message message, int remainingCount, long latency) throws JMSException; } /** diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java new file mode 100644 index 0000000000..f289fe0db2 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java @@ -0,0 +1,251 @@ +/* + * + * 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.qpid.requestreply; + +import junit.framework.Assert; +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +import uk.co.thebadgerset.junit.extensions.AsymptoticTestCase; +import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; +import uk.co.thebadgerset.junit.extensions.util.TestContextProperties; + +import javax.jms.*; + +/** + * PingPongTestPerf is a full round trip ping test, that has been written with the intention of being scaled up to run + * many times simultaneously to simluate many clients/producer/connections. A full round trip ping sends a message from + * a producer to a conumer, then the consumer replies to the message on a temporary queue. + * + *

    A single run of the test using the default JUnit test runner will result in the sending and timing of the number + * of pings specified by the test size and time how long it takes for all of these to complete. This test may be scaled + * up using a suitable JUnit test runner. See {@link uk.co.thebadgerset.junit.extensions.TKTestRunner} for more + * information on how to do this. + * + *

    The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a + * temporary queue for replies. This setup is only established once for all the test repeats, but each test threads + * gets its own connection/producer/consumer, this is only re-established if the connection is lost. + * + *

    The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that + * is the name of the temporary queue, fires off many messages on the original queue and waits for them all to come + * back on the temporary queue. + * + *

    Configurable test properties: message size, transacted or not, persistent or not. Broker connection details. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    + */ +public class PingPongTestPerf extends AsymptoticTestCase +{ + private static Logger _logger = Logger.getLogger(PingPongTestPerf.class); + + /** Thread local to hold the per-thread test setup fields. */ + ThreadLocal threadSetup = new ThreadLocal(); + + // Set up a property reader to extract the test parameters from. Once ContextualProperties is available in + // the project dependencies, use it to get property overrides for configurable tests and to notify the test runner + // of the test parameters to log with the results. It also providers some basic type parsing convenience methods. + // private Properties testParameters = System.getProperties(); + private ParsedProperties testParameters = + TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/); + + public PingPongTestPerf(String name) + { + super(name); + + _logger.debug(testParameters); + + // Sets up the test parameters with defaults. + /*testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME, + Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.MESSAGE_SIZE_PROPNAME, + Integer.toString(PingPongProducer.MESSAGE_SIZE_DEAFULT)); + testParameters.setPropertyIfNull(PingPongProducer.PING_QUEUE_NAME_PROPNAME, + PingPongProducer.PING_QUEUE_NAME_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.PERSISTENT_MODE_PROPNAME, + Boolean.toString(PingPongProducer.PERSISTENT_MODE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.TRANSACTED_PROPNAME, + Boolean.toString(PingPongProducer.TRANSACTED_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.BROKER_PROPNAME, PingPongProducer.BROKER_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.USERNAME_PROPNAME, PingPongProducer.USERNAME_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.PASSWORD_PROPNAME, PingPongProducer.PASSWORD_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.VIRTUAL_HOST_PROPNAME, PingPongProducer.VIRTUAL_HOST_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.VERBOSE_PROPNAME, + Boolean.toString(PingPongProducer.VERBOSE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.RATE_PROPNAME, Integer.toString(PingPongProducer.RATE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.PUBSUB_PROPNAME, + Boolean.toString(PingPongProducer.PUBSUB_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME, + Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.TIMEOUT_PROPNAME, Long.toString(PingPongProducer.TIMEOUT_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.DESTINATION_COUNT_PROPNAME, + Integer.toString(PingPongProducer.DESTINATION_COUNT_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_COMMIT_PROPNAME, + PingPongProducer.FAIL_AFTER_COMMIT_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_COMMIT_PROPNAME, + PingPongProducer.FAIL_BEFORE_COMMIT_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_SEND_PROPNAME, + PingPongProducer.FAIL_AFTER_SEND_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_SEND_PROPNAME, + PingPongProducer.FAIL_BEFORE_SEND_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_ONCE_PROPNAME, PingPongProducer.FAIL_ONCE_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.UNIQUE_DESTS_PROPNAME, + Boolean.toString(PingPongProducer.UNIQUE_DESTS_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.ACK_MODE_PROPNAME, + Integer.toString(PingPongProducer.ACK_MODE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.PAUSE_AFTER_BATCH_PROPNAME, + PingPongProducer.PAUSE_AFTER_BATCH_DEFAULT);*/ + } + + /** + * Compile all the tests into a test suite. + */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Ping-Pong Performance Tests"); + + // Run performance tests in read committed mode. + suite.addTest(new PingPongTestPerf("testPingPongOk")); + + return suite; + } + + private static void setSystemPropertyIfNull(String propName, String propValue) + { + if (System.getProperty(propName) == null) + { + System.setProperty(propName, propValue); + } + } + + public void testPingPongOk(int numPings) throws Exception + { + // Get the per thread test setup to run the test through. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Generate a sample message. This message is already time stamped and has its reply-to destination set. + Message msg = + perThreadSetup._testPingProducer.getTestMessage(perThreadSetup._testPingProducer.getReplyDestinations().get(0), + testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), + testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); + + // Send the message and wait for a reply. + int numReplies = + perThreadSetup._testPingProducer.pingAndWaitForReply(msg, numPings, PingPongProducer.TIMEOUT_DEFAULT, null); + + // Fail the test if the timeout was exceeded. + if (numReplies != numPings) + { + Assert.fail("The ping timed out, got " + numReplies + " out of " + numPings); + } + } + + /** + * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. + */ + public void threadSetUp() + { + try + { + PerThreadSetup perThreadSetup = new PerThreadSetup(); + + // Extract the test set up paramaeters. + String brokerDetails = testParameters.getProperty(PingPongProducer.BROKER_PROPNAME); + String username = testParameters.getProperty(PingPongProducer.USERNAME_PROPNAME); + String password = testParameters.getProperty(PingPongProducer.PASSWORD_PROPNAME); + String virtualPath = testParameters.getProperty(PingPongProducer.VIRTUAL_HOST_PROPNAME); + String destinationName = testParameters.getProperty(PingPongProducer.PING_QUEUE_NAME_PROPNAME); + boolean persistent = testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME); + boolean transacted = testParameters.getPropertyAsBoolean(PingPongProducer.TRANSACTED_PROPNAME); + String selector = testParameters.getProperty(PingPongProducer.SELECTOR_PROPNAME); + boolean verbose = testParameters.getPropertyAsBoolean(PingPongProducer.VERBOSE_PROPNAME); + boolean pubsub = testParameters.getPropertyAsBoolean(PingPongProducer.PUBSUB_PROPNAME); + + synchronized (this) + { + // Establish a bounce back client on the ping queue to bounce back the pings. + perThreadSetup._testPingBouncer = + new PingPongBouncer(brokerDetails, username, password, virtualPath, destinationName, persistent, + transacted, selector, verbose, pubsub); + + // Start the connections for client and producer running. + perThreadSetup._testPingBouncer.getConnection().start(); + + // Establish a ping-pong client on the ping queue to send the pings and receive replies with. + perThreadSetup._testPingProducer = new PingPongProducer(testParameters); + perThreadSetup._testPingProducer.establishConnection(true, true); + perThreadSetup._testPingProducer.start(); + } + + // Attach the per-thread set to the thread. + threadSetup.set(perThreadSetup); + } + catch (Exception e) + { + _logger.warn("There was an exception during per thread setup.", e); + } + } + + /** + * Performs test fixture clean + */ + public void threadTearDown() + { + _logger.debug("public void threadTearDown(): called"); + + try + { + // Get the per thread test fixture. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Close the pingers so that it cleans up its connection cleanly. + synchronized (this) + { + perThreadSetup._testPingProducer.close(); + // perThreadSetup._testPingBouncer.close(); + } + + // Ensure the per thread fixture is reclaimed. + threadSetup.remove(); + } + catch (JMSException e) + { + _logger.warn("There was an exception during per thread tear down."); + } + } + + protected static class PerThreadSetup + { + /** + * Holds the test ping-pong producer. + */ + private PingPongProducer _testPingProducer; + + /** + * Holds the test ping client. + */ + private PingPongBouncer _testPingBouncer; + } +} -- cgit v1.2.1 From 4091ff0951225fdfafcf1f7c73c7c8a3ec524717 Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Fri, 24 Aug 2007 15:58:08 +0000 Subject: updated for using pure JMS git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@569429 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/message/TestMessageFactory.java | 16 +- .../config/AMQConnectionFactoryInitialiser.java | 35 - .../org/apache/qpid/config/AbstractConfig.java | 69 -- .../qpid/config/ConnectionFactoryInitialiser.java | 29 - .../java/org/apache/qpid/config/Connector.java | 40 -- .../org/apache/qpid/config/ConnectorConfig.java | 28 - .../config/JBossConnectionFactoryInitialiser.java | 112 --- .../org/apache/qpid/ping/PingDurableClient.java | 1 - .../org/apache/qpid/ping/PingLatencyTestPerf.java | 8 +- .../org/apache/qpid/ping/PingSendOnlyClient.java | 1 - .../qpid/requestreply/InitialContextHelper.java | 48 ++ .../apache/qpid/requestreply/PingPongBouncer.java | 453 ------------ .../apache/qpid/requestreply/PingPongProducer.java | 774 +++++++++++---------- .../apache/qpid/requestreply/PingPongTestPerf.java | 6 +- .../main/java/org/apache/qpid/topic/Config.java | 326 --------- .../main/java/org/apache/qpid/topic/Listener.java | 303 -------- .../java/org/apache/qpid/topic/MessageFactory.java | 157 ----- .../main/java/org/apache/qpid/topic/Publisher.java | 186 ----- 18 files changed, 479 insertions(+), 2113 deletions(-) delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/Connector.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/InitialContextHelper.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java index 64ccb719b6..4d038db0a8 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java @@ -20,16 +20,12 @@ */ package org.apache.qpid.client.message; -import org.apache.mina.common.ByteBuffer; -import org.apache.mina.common.SimpleByteBufferAllocator; - import javax.jms.JMSException; import javax.jms.Session; import javax.jms.ObjectMessage; import javax.jms.StreamMessage; import javax.jms.BytesMessage; import javax.jms.TextMessage; -import javax.jms.Queue; import javax.jms.DeliveryMode; import javax.jms.Destination; @@ -42,15 +38,6 @@ public class TestMessageFactory return session.createTextMessage(createMessagePayload(size)); } - public static JMSTextMessage newJMSTextMessage(int size, String encoding) throws JMSException - { - ByteBuffer byteBuffer = (new SimpleByteBufferAllocator()).allocate(size, true); - JMSTextMessage message = new JMSTextMessage(byteBuffer, encoding); - message.clearBody(); - message.setText(createMessagePayload(size)); - return message; - } - public static BytesMessage newBytesMessage(Session session, int size) throws JMSException { BytesMessage message = session.createBytesMessage(); @@ -78,7 +65,8 @@ public class TestMessageFactory } /** - * Creates an ObjectMessage with given size and sets the JMS properties (JMSReplyTo and DeliveryMode) + * Creates an ObjectMessage with given size and sets the JMS properties + * (JMSReplyTo and DeliveryMode) * @param session * @param replyDestination * @param size diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java deleted file mode 100644 index cac0064785..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * 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.qpid.config; - -import org.apache.qpid.client.AMQConnectionFactory; -import org.apache.qpid.config.ConnectionFactoryInitialiser; -import org.apache.qpid.config.ConnectorConfig; - -import javax.jms.ConnectionFactory; - -class AMQConnectionFactoryInitialiser implements ConnectionFactoryInitialiser -{ - public ConnectionFactory getFactory(ConnectorConfig config) - { - return new AMQConnectionFactory(config.getHost(), config.getPort(), "/test_path"); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java deleted file mode 100644 index 14db74438f..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * - * 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.qpid.config; - -public abstract class AbstractConfig -{ - public boolean setOptions(String[] argv) - { - try - { - for(int i = 0; i < argv.length - 1; i += 2) - { - String key = argv[i]; - String value = argv[i+1]; - setOption(key, value); - } - return true; - } - catch(Exception e) - { - System.out.println(e.getMessage()); - } - return false; - } - - protected int parseInt(String msg, String i) - { - try - { - return Integer.parseInt(i); - } - catch(NumberFormatException e) - { - throw new RuntimeException(msg + ": " + i, e); - } - } - - protected long parseLong(String msg, String i) - { - try - { - return Long.parseLong(i); - } - catch(NumberFormatException e) - { - throw new RuntimeException(msg + ": " + i, e); - } - } - - public abstract void setOption(String key, String value); -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java deleted file mode 100644 index a9984eb09a..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * - * 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.qpid.config; - -import javax.jms.ConnectionFactory; -import javax.jms.JMSException; - -public interface ConnectionFactoryInitialiser -{ - public ConnectionFactory getFactory(ConnectorConfig config) throws JMSException; -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/Connector.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/Connector.java deleted file mode 100644 index ff2377f087..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/config/Connector.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * 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.qpid.config; - -import javax.jms.Connection; -import javax.jms.ConnectionFactory; - -public class Connector -{ - public Connection createConnection(ConnectorConfig config) throws Exception - { - return getConnectionFactory(config).createConnection(); - } - - ConnectionFactory getConnectionFactory(ConnectorConfig config) throws Exception - { - String factory = config.getFactory(); - if(factory == null) factory = AMQConnectionFactoryInitialiser.class.getName(); - System.out.println("Using " + factory); - return ((ConnectionFactoryInitialiser) Class.forName(factory).newInstance()).getFactory(config); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java deleted file mode 100644 index b120ed3f12..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * - * 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.qpid.config; - -public interface ConnectorConfig -{ - public String getHost(); - public int getPort(); - public String getFactory(); -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java deleted file mode 100644 index a0248a8f79..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * - * 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.qpid.config; - -import org.apache.qpid.config.ConnectionFactoryInitialiser; -import org.apache.qpid.config.ConnectorConfig; -import org.apache.qpid.client.JMSAMQException; - -import javax.jms.ConnectionFactory; -import javax.jms.JMSException; -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; -import javax.management.MBeanException; -import javax.naming.InitialContext; -import javax.naming.NamingException; -import javax.naming.NameNotFoundException; -import java.util.Hashtable; - -public class JBossConnectionFactoryInitialiser implements ConnectionFactoryInitialiser -{ - public ConnectionFactory getFactory(ConnectorConfig config) throws JMSException - { - ConnectionFactory cf = null; - InitialContext ic = null; - Hashtable ht = new Hashtable(); - ht.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); - String jbossHost = System.getProperty("jboss.host", "eqd-lxamq01"); - String jbossPort = System.getProperty("jboss.port", "1099"); - ht.put(InitialContext.PROVIDER_URL, "jnp://" + jbossHost + ":" + jbossPort); - ht.put(InitialContext.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); - - try - { - ic = new InitialContext(ht); - if (!doesDestinationExist("topictest.messages", ic)) - { - deployTopic("topictest.messages", ic); - } - if (!doesDestinationExist("topictest.control", ic)) - { - deployTopic("topictest.control", ic); - } - - cf = (ConnectionFactory) ic.lookup("/ConnectionFactory"); - return cf; - } - catch (NamingException e) - { - throw new JMSAMQException("Unable to lookup object: " + e, e); - } - catch (Exception e) - { - throw new JMSAMQException("Error creating topic: " + e, e); - } - } - - private boolean doesDestinationExist(String name, InitialContext ic) throws Exception - { - try - { - ic.lookup("/" + name); - } - catch (NameNotFoundException e) - { - return false; - } - return true; - } - - private void deployTopic(String name, InitialContext ic) throws Exception - { - MBeanServerConnection mBeanServer = lookupMBeanServerProxy(ic); - - ObjectName serverObjectName = new ObjectName("jboss.messaging:service=ServerPeer"); - - String jndiName = "/" + name; - try - { - mBeanServer.invoke(serverObjectName, "createTopic", - new Object[]{name, jndiName}, - new String[]{"java.lang.String", "java.lang.String"}); - } - catch (MBeanException e) - { - System.err.println("Error: " + e); - System.err.println("Cause: " + e.getCause()); - } - } - - private MBeanServerConnection lookupMBeanServerProxy(InitialContext ic) throws NamingException - { - return (MBeanServerConnection) ic.lookup("jmx/invoker/RMIAdaptor"); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java index db6f384914..2750790354 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java @@ -116,7 +116,6 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList defaults.setProperty(PERSISTENT_MODE_PROPNAME, "true"); defaults.setProperty(TX_BATCH_SIZE_PROPNAME, "10"); defaults.setProperty(RATE_PROPNAME, "20"); - defaults.setProperty(DURABLE_DESTS_PROPNAME, "true"); defaults.setProperty(NUM_MESSAGES_TO_ACTION_PROPNAME, NUM_MESSAGES_TO_ACTION_DEFAULT); } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java index 55414664da..f05d13e4e2 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java @@ -25,9 +25,6 @@ import junit.framework.TestSuite; import org.apache.log4j.Logger; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.message.AMQMessage; -import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.requestreply.PingPongProducer; import uk.co.thebadgerset.junit.extensions.TimingController; @@ -36,7 +33,6 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; import javax.jms.JMSException; import javax.jms.Message; -import javax.jms.ObjectMessage; import java.util.Collections; import java.util.HashMap; @@ -246,9 +242,7 @@ public class PingLatencyTestPerf extends PingTestPerf implements TimingControlle public BatchedResultsListener(int batchSize) { _batchSize = batchSize; - _strictAMQP = - Boolean.parseBoolean(System.getProperties().getProperty(AMQSession.STRICT_AMQP, - AMQSession.STRICT_AMQP_DEFAULT)); + _strictAMQP = false; } /** diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java index 2879f0c322..150f7c0d52 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java @@ -26,7 +26,6 @@ import java.util.Properties; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; -import javax.jms.ObjectMessage; import org.apache.log4j.Logger; diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/InitialContextHelper.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/InitialContextHelper.java new file mode 100644 index 0000000000..067aad4095 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/InitialContextHelper.java @@ -0,0 +1,48 @@ +/* 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.qpid.requestreply; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import java.util.Properties; +import java.io.InputStream; +import java.io.IOException; + +/** + * + * + */ +public class InitialContextHelper +{ + + public static Context getInitialContext(String propertyFile) throws IOException, NamingException + { + if ((propertyFile == null) || (propertyFile.length() == 0)) + { + propertyFile = "/perftests.properties"; + } + + Properties fileProperties = new Properties(); + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + // NB: Need to change path to reflect package if moving classes around ! + InputStream is = cl.getResourceAsStream(propertyFile); + fileProperties.load(is); + return new InitialContext(fileProperties); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java deleted file mode 100644 index 82b36bf233..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java +++ /dev/null @@ -1,453 +0,0 @@ -/* - * - * 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.qpid.requestreply; - -import java.io.IOException; -import java.net.InetAddress; -import java.text.SimpleDateFormat; -import java.util.Date; - -import javax.jms.*; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.jms.ConnectionListener; -import org.apache.qpid.jms.Session; -import org.apache.qpid.topic.Config; -import org.apache.qpid.exchange.ExchangeDefaults; - -/** - * PingPongBouncer is a message listener the bounces back messages to their reply to destination. This is used to return - * ping messages generated by {@link org.apache.qpid.requestreply.PingPongProducer} but could be used for other purposes - * too. - * - *

    The correlation id from the received message is extracted, and placed into the reply as the correlation id. Messages - * are bounced back to their reply-to destination. The original sender of the message has the option to use either a unique - * temporary queue or the correlation id to correlate the original message to the reply. - * - *

    There is a verbose mode flag which causes information about each ping to be output to the console - * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should - * be disabled for real timing tests as writing to the console will slow things down. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Bounce back messages to their reply to destination. - *
    Provide command line invocation to start the bounce back on a configurable broker url. - *
    - * - * @todo Replace the command line parsing with a neater tool. - * - * @todo Make verbose accept a number of messages, only prints to console every X messages. - */ -public class PingPongBouncer implements MessageListener -{ - private static final Logger _logger = Logger.getLogger(PingPongBouncer.class); - - /** The default prefetch size for the message consumer. */ - private static final int PREFETCH = 1; - - /** The default no local flag for the message consumer. */ - private static final boolean NO_LOCAL = true; - - private static final String DEFAULT_DESTINATION_NAME = "ping"; - - /** The default exclusive flag for the message consumer. */ - private static final boolean EXCLUSIVE = false; - - /** A convenient formatter to use when time stamping output. */ - protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); - - /** Used to indicate that the reply generator should log timing info to the console (logger info level). */ - private boolean _verbose = false; - - /** Determines whether this bounce back client bounces back messages persistently. */ - private boolean _persistent = false; - - private Destination _consumerDestination; - - /** Keeps track of the response destination of the previous message for the last reply to producer cache. */ - private Destination _lastResponseDest; - - /** The producer for sending replies with. */ - private MessageProducer _replyProducer; - - /** The consumer controlSession. */ - private Session _consumerSession; - - /** The producer controlSession. */ - private Session _producerSession; - - /** Holds the connection to the broker. */ - private AMQConnection _connection; - - /** Flag used to indicate if this is a point to point or pub/sub ping client. */ - private boolean _isPubSub = false; - - /** - * This flag is used to indicate that the user should be prompted to kill a broker, in order to test - * failover, immediately before committing a transaction. - */ - protected boolean _failBeforeCommit = false; - - /** - * This flag is used to indicate that the user should be prompted to a kill a broker, in order to test - * failover, immediate after committing a transaction. - */ - protected boolean _failAfterCommit = false; - - /** - * Creates a PingPongBouncer on the specified producer and consumer sessions. - * - * @param brokerDetails The addresses of the brokers to connect to. - * @param username The broker username. - * @param password The broker password. - * @param virtualpath The virtual host name within the broker. - * @param destinationName The name of the queue to receive pings on - * (or root of the queue name where many queues are generated). - * @param persistent A flag to indicate that persistent message should be used. - * @param transacted A flag to indicate that pings should be sent within transactions. - * @param selector A message selector to filter received pings with. - * @param verbose A flag to indicate that message timings should be sent to the console. - * - * @throws Exception All underlying exceptions allowed to fall through. This is only test code... - */ - public PingPongBouncer(String brokerDetails, String username, String password, String virtualpath, - String destinationName, boolean persistent, boolean transacted, String selector, boolean verbose, - boolean pubsub) throws Exception - { - // Create a client id to uniquely identify this client. - InetAddress address = InetAddress.getLocalHost(); - String clientId = address.getHostName() + System.currentTimeMillis(); - _verbose = verbose; - _persistent = persistent; - setPubSub(pubsub); - // Connect to the broker. - setConnection(new AMQConnection(brokerDetails, username, password, clientId, virtualpath)); - _logger.info("Connected with URL:" + getConnection().toURL()); - - // Set up the failover notifier. - getConnection().setConnectionListener(new FailoverNotifier()); - - // Create a controlSession to listen for messages on and one to send replies on, transactional depending on the - // command line option. - _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); - _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); - - // Create the queue to listen for message on. - createConsumerDestination(destinationName); - MessageConsumer consumer = - _consumerSession.createConsumer(_consumerDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); - - // Create a producer for the replies, without a default destination. - _replyProducer = _producerSession.createProducer(null); - _replyProducer.setDisableMessageTimestamp(true); - _replyProducer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - - // Set this up to listen for messages on the queue. - consumer.setMessageListener(this); - } - - /** - * Starts a stand alone ping-pong client running in verbose mode. - * - * @param args - */ - public static void main(String[] args) throws Exception - { - System.out.println("Starting..."); - - // Display help on the command line. - if (args.length == 0) - { - _logger.info("Running test with default values..."); - //usage(); - //System.exit(0); - } - - // Extract all command line parameters. - Config config = new Config(); - config.setOptions(args); - String brokerDetails = config.getHost() + ":" + config.getPort(); - String virtualpath = "test"; - String destinationName = config.getDestination(); - if (destinationName == null) - { - destinationName = DEFAULT_DESTINATION_NAME; - } - - String selector = config.getSelector(); - boolean transacted = config.isTransacted(); - boolean persistent = config.usePersistentMessages(); - boolean pubsub = config.isPubSub(); - boolean verbose = true; - - //String selector = null; - - // Instantiate the ping pong client with the command line options and start it running. - PingPongBouncer pingBouncer = - new PingPongBouncer(brokerDetails, "guest", "guest", virtualpath, destinationName, persistent, transacted, - selector, verbose, pubsub); - pingBouncer.getConnection().start(); - - System.out.println("Waiting..."); - } - - private static void usage() - { - System.err.println("Usage: PingPongBouncer \n" + "-host : broker host\n" + "-port : broker port\n" - + "-destinationname : queue/topic name\n" + "-transacted : (true/false). Default is false\n" - + "-persistent : (true/false). Default is false\n" - + "-pubsub : (true/false). Default is false\n" + "-selector : selector string\n"); - } - - /** - * This is a callback method that is notified of all messages for which this has been registered as a message - * listener on a message consumer. It sends a reply (pong) to all messages it receieves on the reply to - * destination of the message. - * - * @param message The message that triggered this callback. - */ - public void onMessage(Message message) - { - try - { - String messageCorrelationId = message.getJMSCorrelationID(); - if (_verbose) - { - _logger.info(timestampFormatter.format(new Date()) + ": Got ping with correlation id, " - + messageCorrelationId); - } - - // Get the reply to destination from the message and check it is set. - Destination responseDest = message.getJMSReplyTo(); - - if (responseDest == null) - { - _logger.debug("Cannot send reply because reply-to destination is null."); - - return; - } - - // Spew out some timing information if verbose mode is on. - if (_verbose) - { - Long timestamp = message.getLongProperty("timestamp"); - - if (timestamp != null) - { - long diff = System.currentTimeMillis() - timestamp; - _logger.info("Time to bounce point: " + diff); - } - } - - // Correlate the reply to the original. - message.setJMSCorrelationID(messageCorrelationId); - - // Send the receieved message as the pong reply. - _replyProducer.send(responseDest, message); - - if (_verbose) - { - _logger.info(timestampFormatter.format(new Date()) + ": Sent reply with correlation id, " - + messageCorrelationId); - } - - // Commit the transaction if running in transactional mode. - commitTx(_producerSession); - } - catch (JMSException e) - { - _logger.debug("There was a JMSException: " + e.getMessage(), e); - } - } - - /** - * Gets the underlying connection that this ping client is running on. - * - * @return The underlying connection that this ping client is running on. - */ - public AMQConnection getConnection() - { - return _connection; - } - - /** - * Sets the connection that this ping client is using. - * - * @param connection The ping connection. - */ - public void setConnection(AMQConnection connection) - { - this._connection = connection; - } - - /** - * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic. - * - * @param pubsub true if this client is pinging a topic, false if it is pinging a queue. - */ - public void setPubSub(boolean pubsub) - { - _isPubSub = pubsub; - } - - /** - * Checks whether this client is a p2p or pub/sub ping client. - * - * @return true if this client is pinging a topic, false if it is pinging a queue. - */ - public boolean isPubSub() - { - return _isPubSub; - } - - /** - * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not - * a transactional controlSession, this method does nothing. - * - *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the - * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker - * after the commit is applied. - * - * @throws javax.jms.JMSException If the commit fails and then the rollback fails. - */ - protected void commitTx(Session session) throws JMSException - { - if (session.getTransacted()) - { - try - { - if (_failBeforeCommit) - { - _logger.trace("Failing Before Commit"); - doFailover(); - } - - session.commit(); - - if (_failAfterCommit) - { - _logger.trace("Failing After Commit"); - doFailover(); - } - - _logger.trace("Session Commited."); - } - catch (JMSException e) - { - _logger.trace("JMSException on commit:" + e.getMessage(), e); - - try - { - session.rollback(); - _logger.debug("Message rolled back."); - } - catch (JMSException jmse) - { - _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); - - // Both commit and rollback failed. Throw the rollback exception. - throw jmse; - } - } - } - } - - /** - * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block - * until the user supplied some input on the terminal. - * - * @param broker The name of the broker to terminate. - */ - protected void doFailover(String broker) - { - System.out.println("Kill Broker " + broker + " now."); - try - { - System.in.read(); - } - catch (IOException e) - { } - - System.out.println("Continuing."); - } - - /** - * Prompts the user to terminate the broker, in order to test failover functionality. This method will block - * until the user supplied some input on the terminal. - */ - protected void doFailover() - { - System.out.println("Kill Broker now."); - try - { - System.in.read(); - } - catch (IOException e) - { } - - System.out.println("Continuing."); - - } - - private void createConsumerDestination(String name) - { - if (isPubSub()) - { - _consumerDestination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, name); - } - else - { - _consumerDestination = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, name); - } - } - - /** - * A connection listener that logs out any failover complete events. Could do more interesting things with this - * at some point... - */ - public static class FailoverNotifier implements ConnectionListener - { - public void bytesSent(long count) - { } - - public void bytesReceived(long count) - { } - - public boolean preFailover(boolean redirect) - { - return true; - } - - public boolean preResubscribe() - { - return true; - } - - public void failoverComplete() - { - _logger.info("App got failover complete callback."); - } - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index bd34fd8f20..638f5ae8c0 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -21,17 +21,8 @@ package org.apache.qpid.requestreply; import org.apache.log4j.Logger; -import org.apache.log4j.NDC; -import org.apache.qpid.AMQException; -import org.apache.qpid.client.*; -import org.apache.qpid.client.message.AMQMessage; import org.apache.qpid.client.message.TestMessageFactory; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.jms.MessageProducer; -import org.apache.qpid.jms.Session; -import org.apache.qpid.url.URLSyntaxException; import org.apache.qpid.util.CommandLineParser; import uk.co.thebadgerset.junit.extensions.BatchedThrottle; @@ -39,6 +30,7 @@ import uk.co.thebadgerset.junit.extensions.Throttle; import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; import javax.jms.*; +import javax.naming.Context; import java.io.IOException; import java.net.InetAddress; @@ -56,16 +48,16 @@ import java.util.concurrent.atomic.AtomicLong; * to its own messages and does not send replies (see {@link org.apache.qpid.ping.PingClient}). The intention of ping * pong producer is that it is a swiss-army knife test client that makes almost every aspect of its behaviour * configurable. - * + *

    *

    The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. This * means that this class has to do some work to correlate pings with pongs; it expectes the original message correlation * id in the ping to be bounced back in the reply correlation id. - * + *

    *

    This ping tool accepts a vast number of configuration options, all of which are passed in to the constructor. It * can ping topics or queues; ping multiple destinations; do persistent pings; send messages of any size; do pings within * transactions; control the number of pings to send in each transaction; limit its sending rate; and perform failover * testing. A complete list of accepted parameters, default values and comments on their usage is provided here: - * + *

    *

    *
    Parameters
    Parameter Default Comments *
    messageSize 0 Message size in bytes. Not including any headers. @@ -92,27 +84,27 @@ import java.util.concurrent.atomic.AtomicLong; *
    uniqueDests true Whether each receivers only listens to one ping destination or all. *
    durableDests false Whether or not durable destinations are used. *
    ackMode AUTO_ACK The message acknowledgement mode. Possible values are: - * 0 - SESSION_TRANSACTED - * 1 - AUTO_ACKNOWLEDGE - * 2 - CLIENT_ACKNOWLEDGE - * 3 - DUPS_OK_ACKNOWLEDGE - * 257 - NO_ACKNOWLEDGE - * 258 - PRE_ACKNOWLEDGE + * 0 - SESSION_TRANSACTED + * 1 - AUTO_ACKNOWLEDGE + * 2 - CLIENT_ACKNOWLEDGE + * 3 - DUPS_OK_ACKNOWLEDGE + * 257 - NO_ACKNOWLEDGE + * 258 - PRE_ACKNOWLEDGE *
    consTransacted false Whether or not consumers use transactions. Defaults to the same value - * as the 'transacted' option if not seperately defined. + * as the 'transacted' option if not seperately defined. *
    consAckMode AUTO_ACK The message acknowledgement mode for consumers. Defaults to the same - * value as 'ackMode' if not seperately defined. + * value as 'ackMode' if not seperately defined. *
    maxPending 0 The maximum size in bytes, of messages sent but not yet received. - * Limits the volume of messages currently buffered on the client - * or broker. Can help scale test clients by limiting amount of buffered - * data to avoid out of memory errors. + * Limits the volume of messages currently buffered on the client + * or broker. Can help scale test clients by limiting amount of buffered + * data to avoid out of memory errors. *
    - * + *

    *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so by * starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is also * registered to terminate the ping-pong loop cleanly. - * + *

    *

    *
    CRC Card
    Responsibilities Collaborations *
    Provide a ping and wait for all responses cycle. @@ -120,168 +112,249 @@ import java.util.concurrent.atomic.AtomicLong; *
    * * @todo Make the message listener a static for all replies to be sent to? It won't be any more of a bottle neck than having - * one per PingPongProducer, as will synchronize on message correlation id, allowing threads to process messages - * concurrently for different ids. Needs to be static so that when using a chained message listener and shared - * destinations between multiple PPPs, it gets notified about all replies, not just those that happen to be picked up - * by the PPP that it is atteched to. - * + * one per PingPongProducer, as will synchronize on message correlation id, allowing threads to process messages + * concurrently for different ids. Needs to be static so that when using a chained message listener and shared + * destinations between multiple PPPs, it gets notified about all replies, not just those that happen to be picked up + * by the PPP that it is atteched to. * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock pair. - * Obtain read lock on all messages, before decrementing the message count. At the end of the on message method add a - * block that obtains the write lock for the very last message, releases any waiting producer. Means that the last - * message waits until all other messages have been handled before releasing producers but allows messages to be - * processed concurrently, unlike the current synchronized block. - * + * Obtain read lock on all messages, before decrementing the message count. At the end of the on message method add a + * block that obtains the write lock for the very last message, releases any waiting producer. Means that the last + * message waits until all other messages have been handled before releasing producers but allows messages to be + * processed concurrently, unlike the current synchronized block. * @todo Get rid of pauses between batches, it will impact the timing statistics, and generate meanigless timings. - * Instead make mina use a bounded blocking buffer, or other form of back pressure, to stop data being written - * faster than it can be sent. + * Instead make mina use a bounded blocking buffer, or other form of back pressure, to stop data being written + * faster than it can be sent. */ public class PingPongProducer implements Runnable /*, MessageListener*/, ExceptionListener { - /** Used for debugging. */ - private static final Logger log = Logger.getLogger(PingPongProducer.class); + /** + * Used for debugging. + */ + private static final Logger _log = Logger.getLogger(PingPongProducer.class); - /** Holds the name of the property to get the test message size from. */ + /** + * Helds the factory name + */ + public static final String FACTORY_NAME_PROPNAME = "factoryName"; + public static final String FACTORY_NAME_DEAFULT = "local"; + + /** + * Helds the file properties name + */ + public static final String FILE_PROPERTIES_PROPNAME = "properties"; + public static final String FILE_PROPERTIES_DEAFULT = "/perftests.properties"; + + /** + * Holds the name of the property to get the test message size from. + */ public static final String MESSAGE_SIZE_PROPNAME = "messageSize"; - /** Used to set up a default message size. */ + /** + * Used to set up a default message size. + */ public static final int MESSAGE_SIZE_DEAFULT = 0; - /** Holds the name of the property to get the ping queue name from. */ + /** + * Holds the name of the property to get the ping queue name from. + */ public static final String PING_QUEUE_NAME_PROPNAME = "destinationName"; - /** Holds the name of the default destination to send pings on. */ + /** + * Holds the name of the default destination to send pings on. + */ public static final String PING_QUEUE_NAME_DEFAULT = "ping"; - /** Holds the name of the property to get the test delivery mode from. */ + /** + * Holds the name of the property to get the test delivery mode from. + */ public static final String PERSISTENT_MODE_PROPNAME = "persistent"; - /** Holds the message delivery mode to use for the test. */ + /** + * Holds the message delivery mode to use for the test. + */ public static final boolean PERSISTENT_MODE_DEFAULT = false; - /** Holds the name of the property to get the test transactional mode from. */ + /** + * Holds the name of the property to get the test transactional mode from. + */ public static final String TRANSACTED_PROPNAME = "transacted"; - /** Holds the transactional mode to use for the test. */ + /** + * Holds the transactional mode to use for the test. + */ public static final boolean TRANSACTED_DEFAULT = false; public static final String CONSUMER_TRANSACTED_PROPNAME = "consTransacted"; public static final boolean CONSUMER_TRANSACTED_DEFAULT = false; - /** Holds the name of the property to get the test broker url from. */ - public static final String BROKER_PROPNAME = "broker"; - - /** Holds the default broker url for the test. */ - public static final String BROKER_DEFAULT = "tcp://localhost:5672"; - - /** Holds the name of the property to get the test broker virtual path. */ - public static final String VIRTUAL_HOST_PROPNAME = "virtualHost"; - - /** Holds the default virtual path for the test. */ - public static final String VIRTUAL_HOST_DEFAULT = ""; - - /** Holds the name of the property to get the message rate from. */ + /** + * Holds the name of the property to get the message rate from. + */ public static final String RATE_PROPNAME = "rate"; - /** Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. */ + /** + * Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. + */ public static final int RATE_DEFAULT = 0; - /** Holds the name of the property to get the verbose mode proeprty from. */ + /** + * Holds the name of the property to get the verbose mode proeprty from. + */ public static final String VERBOSE_PROPNAME = "verbose"; - /** Holds the default verbose mode. */ + /** + * Holds the default verbose mode. + */ public static final boolean VERBOSE_DEFAULT = false; - /** Holds the name of the property to get the p2p or pub/sub messaging mode from. */ + /** + * Holds the name of the property to get the p2p or pub/sub messaging mode from. + */ public static final String PUBSUB_PROPNAME = "pubsub"; - /** Holds the pub/sub mode default, true means ping a topic, false means ping a queue. */ + /** + * Holds the pub/sub mode default, true means ping a topic, false means ping a queue. + */ public static final boolean PUBSUB_DEFAULT = false; - /** Holds the name of the property to get the fail after commit flag from. */ + /** + * Holds the name of the property to get the fail after commit flag from. + */ public static final String FAIL_AFTER_COMMIT_PROPNAME = "failAfterCommit"; - /** Holds the default failover after commit test flag. */ + /** + * Holds the default failover after commit test flag. + */ public static final boolean FAIL_AFTER_COMMIT_DEFAULT = false; - /** Holds the name of the proeprty to get the fail before commit flag from. */ + /** + * Holds the name of the proeprty to get the fail before commit flag from. + */ public static final String FAIL_BEFORE_COMMIT_PROPNAME = "failBeforeCommit"; - /** Holds the default failover before commit test flag. */ + /** + * Holds the default failover before commit test flag. + */ public static final boolean FAIL_BEFORE_COMMIT_DEFAULT = false; - /** Holds the name of the proeprty to get the fail after send flag from. */ + /** + * Holds the name of the proeprty to get the fail after send flag from. + */ public static final String FAIL_AFTER_SEND_PROPNAME = "failAfterSend"; - /** Holds the default failover after send test flag. */ + /** + * Holds the default failover after send test flag. + */ public static final boolean FAIL_AFTER_SEND_DEFAULT = false; - /** Holds the name of the property to get the fail before send flag from. */ + /** + * Holds the name of the property to get the fail before send flag from. + */ public static final String FAIL_BEFORE_SEND_PROPNAME = "failBeforeSend"; - /** Holds the default failover before send test flag. */ + /** + * Holds the default failover before send test flag. + */ public static final boolean FAIL_BEFORE_SEND_DEFAULT = false; - /** Holds the name of the property to get the fail once flag from. */ + /** + * Holds the name of the property to get the fail once flag from. + */ public static final String FAIL_ONCE_PROPNAME = "failOnce"; - /** The default failover once flag, true means only do one failover, false means failover on every commit cycle. */ + /** + * The default failover once flag, true means only do one failover, false means failover on every commit cycle. + */ public static final boolean FAIL_ONCE_DEFAULT = true; - /** Holds the name of the property to get the broker access username from. */ + /** + * Holds the name of the property to get the broker access username from. + */ public static final String USERNAME_PROPNAME = "username"; - /** Holds the default broker log on username. */ + /** + * Holds the default broker _log on username. + */ public static final String USERNAME_DEFAULT = "guest"; - /** Holds the name of the property to get the broker access password from. */ + /** + * Holds the name of the property to get the broker access password from. + */ public static final String PASSWORD_PROPNAME = "password"; - /** Holds the default broker log on password. */ + /** + * Holds the default broker _log on password. + */ public static final String PASSWORD_DEFAULT = "guest"; - /** Holds the name of the proeprty to get the. */ + /** + * Holds the name of the proeprty to get the. + */ public static final String SELECTOR_PROPNAME = "selector"; - /** Holds the default message selector. */ + /** + * Holds the default message selector. + */ public static final String SELECTOR_DEFAULT = ""; - /** Holds the name of the property to get the destination count from. */ + /** + * Holds the name of the property to get the destination count from. + */ public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; - /** Defines the default number of destinations to ping. */ + /** + * Defines the default number of destinations to ping. + */ public static final int DESTINATION_COUNT_DEFAULT = 1; - /** Holds the name of the property to get the number of consumers per destination from. */ + /** + * Holds the name of the property to get the number of consumers per destination from. + */ public static final String NUM_CONSUMERS_PROPNAME = "numConsumers"; - /** Defines the default number consumers per destination. */ + /** + * Defines the default number consumers per destination. + */ public static final int NUM_CONSUMERS_DEFAULT = 1; - /** Holds the name of the property to get the waiting timeout for response messages. */ + /** + * Holds the name of the property to get the waiting timeout for response messages. + */ public static final String TIMEOUT_PROPNAME = "timeout"; - /** Default time to wait before assuming that a ping has timed out. */ + /** + * Default time to wait before assuming that a ping has timed out. + */ public static final long TIMEOUT_DEFAULT = 30000; - /** Holds the name of the property to get the commit batch size from. */ + /** + * Holds the name of the property to get the commit batch size from. + */ public static final String TX_BATCH_SIZE_PROPNAME = "commitBatchSize"; - /** Defines the default number of pings to send in each transaction when running transactionally. */ + /** + * Defines the default number of pings to send in each transaction when running transactionally. + */ public static final int TX_BATCH_SIZE_DEFAULT = 1; - /** Holds the name of the property to get the unique destinations flag from. */ + /** + * Holds the name of the property to get the unique destinations flag from. + */ public static final String UNIQUE_DESTS_PROPNAME = "uniqueDests"; - /** Defines the default value for the unique destinations property. */ + /** + * Defines the default value for the unique destinations property. + */ public static final boolean UNIQUE_DESTS_DEFAULT = true; - public static final String DURABLE_DESTS_PROPNAME = "durableDests"; - public static final boolean DURABLE_DESTS_DEFAULT = false; - - /** Holds the name of the proeprty to get the message acknowledgement mode from. */ + /** + * Holds the name of the proeprty to get the message acknowledgement mode from. + */ public static final String ACK_MODE_PROPNAME = "ackMode"; - /** Defines the default message acknowledgement mode. */ + /** + * Defines the default message acknowledgement mode. + */ public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; public static final String CONSUMER_ACK_MODE_PROPNAME = "consAckMode"; @@ -290,27 +363,37 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti public static final String MAX_PENDING_PROPNAME = "maxPending"; public static final int MAX_PENDING_DEFAULT = 0; - /** Defines the default prefetch size to use when consuming messages. */ + /** + * Defines the default prefetch size to use when consuming messages. + */ public static final int PREFETCH_DEFAULT = 100; - /** Defines the default value of the no local flag to use when consuming messages. */ + /** + * Defines the default value of the no local flag to use when consuming messages. + */ public static final boolean NO_LOCAL_DEFAULT = false; - /** Defines the default value of the exclusive flag to use when consuming messages. */ + /** + * Defines the default value of the exclusive flag to use when consuming messages. + */ public static final boolean EXCLUSIVE_DEFAULT = false; - /** Holds the name of the property to store nanosecond timestamps in ping messages with. */ + /** + * Holds the name of the property to store nanosecond timestamps in ping messages with. + */ public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp"; - /** Holds the default configuration properties. */ + /** + * Holds the default configuration properties. + */ public static ParsedProperties defaults = new ParsedProperties(); static { - defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT); + defaults.setPropertyIfNull(FILE_PROPERTIES_PROPNAME, FILE_PROPERTIES_DEAFULT); + defaults.setPropertyIfNull(FACTORY_NAME_PROPNAME, FACTORY_NAME_DEAFULT); defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT); defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT); - defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT); defaults.setPropertyIfNull(PING_QUEUE_NAME_PROPNAME, PING_QUEUE_NAME_DEFAULT); defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT); defaults.setPropertyIfNull(TRANSACTED_PROPNAME, TRANSACTED_DEFAULT); @@ -322,7 +405,6 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT); defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT); defaults.setPropertyIfNull(UNIQUE_DESTS_PROPNAME, UNIQUE_DESTS_DEFAULT); - defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT); defaults.setPropertyIfNull(FAIL_BEFORE_COMMIT_PROPNAME, FAIL_BEFORE_COMMIT_DEFAULT); defaults.setPropertyIfNull(FAIL_AFTER_COMMIT_PROPNAME, FAIL_AFTER_COMMIT_DEFAULT); defaults.setPropertyIfNull(FAIL_BEFORE_SEND_PROPNAME, FAIL_BEFORE_SEND_DEFAULT); @@ -336,6 +418,8 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT); } + protected String _factoryName; + protected String _fileProperties; protected String _brokerDetails; protected String _username; protected String _password; @@ -345,54 +429,81 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti protected boolean _transacted; protected boolean _consTransacted; - /** Determines whether this producer sends persistent messages. */ + /** + * Determines whether this producer sends persistent messages. + */ protected boolean _persistent; - /** Holds the acknowledgement mode used for sending and receiving messages. */ + /** + * Holds the acknowledgement mode used for sending and receiving messages. + */ protected int _ackMode; protected int _consAckMode; - /** Determines what size of messages this producer sends. */ + /** + * Determines what size of messages this producer sends. + */ protected int _messageSize; - /** Used to indicate that the ping loop should print out whenever it pings. */ + /** + * Used to indicate that the ping loop should print out whenever it pings. + */ protected boolean _verbose; - /** Flag used to indicate if this is a point to point or pub/sub ping client. */ + /** + * Flag used to indicate if this is a point to point or pub/sub ping client. + */ protected boolean _isPubSub; - /** Flag used to indicate if the destinations should be unique client. */ + /** + * Flag used to indicate if the destinations should be unique client. + */ protected boolean _isUnique; - /** Flag used to indicate that durable destination should be used. */ - protected boolean _isDurable; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ + /** + * Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. + */ protected boolean _failBeforeCommit; - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ + /** + * Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. + */ protected boolean _failAfterCommit; - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ + /** + * Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. + */ protected boolean _failBeforeSend; - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ + /** + * Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. + */ protected boolean _failAfterSend; - /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ + /** + * Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. + */ protected boolean _failOnce; - /** Holds the number of sends that should be performed in every transaction when using transactions. */ + /** + * Holds the number of sends that should be performed in every transaction when using transactions. + */ protected int _txBatchSize; - /** Holds the number of destinations to ping. */ + /** + * Holds the number of destinations to ping. + */ protected int _noOfDestinations; - /** Holds the number of consumers per destination. */ + /** + * Holds the number of consumers per destination. + */ protected int _noOfConsumers; - /** Holds the maximum send rate in herz. */ + /** + * Holds the maximum send rate in herz. + */ protected int _rate; /** @@ -407,10 +518,14 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ protected Object _sendPauseMonitor = new Object(); - /** Keeps a count of the number of message currently sent but not received. */ + /** + * Keeps a count of the number of message currently sent but not received. + */ protected AtomicInteger _unreceived = new AtomicInteger(0); - /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ + /** + * A source for providing sequential unique correlation ids. These will be unique within the same JVM. + */ private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); /** @@ -418,33 +533,51 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * ping producers on the same JVM. */ private static Map perCorrelationIds = - Collections.synchronizedMap(new HashMap()); + Collections.synchronizedMap(new HashMap()); - /** A convenient formatter to use when time stamping output. */ + /** + * A convenient formatter to use when time stamping output. + */ protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); - /** Holds the connection to the broker. */ + /** + * Holds the connection to the broker. + */ protected Connection _connection; - /** Holds the consumer connections. */ + /** + * Holds the consumer connections. + */ protected Connection[] _consumerConnection; - /** Holds the controlSession on which ping replies are received. */ + /** + * Holds the controlSession on which ping replies are received. + */ protected Session[] _consumerSession; - /** Holds the producer controlSession, needed to create ping messages. */ - protected Session _producerSession; + /** + * Holds the producer controlSession, needed to create ping messages. + */ + protected Session _producerSession = (Session) _connection.createSession(_transacted, _ackMode); - /** Holds the destination where the response messages will arrive. */ + /** + * Holds the destination where the response messages will arrive. + */ protected Destination _replyDestination; - /** Holds the set of destinations that this ping producer pings. */ + /** + * Holds the set of destinations that this ping producer pings. + */ protected List _pingDestinations; - /** Used to restrict the sending rate to a specified limit. */ + /** + * Used to restrict the sending rate to a specified limit. + */ protected Throttle _rateLimiter; - /** Holds a message listener that this message listener chains all its messages to. */ + /** + * Holds a message listener that this message listener chains all its messages to. + */ protected ChainedMessageListener _chainedMessageListener = null; /** @@ -459,20 +592,29 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ protected AtomicInteger _queueSharedID = new AtomicInteger(); - /** Used to tell the ping loop when to terminate, it only runs while this is true. */ + /** + * Used to tell the ping loop when to terminate, it only runs while this is true. + */ protected boolean _publish = true; - /** Holds the message producer to send the pings through. */ + /** + * Holds the message producer to send the pings through. + */ protected MessageProducer _producer; - /** Holds the message consumer to receive the ping replies through. */ + /** + * Holds the message consumer to receive the ping replies through. + */ protected MessageConsumer[] _consumer; - /** The prompt to display when asking the user to kill the broker for failover testing. */ + /** + * The prompt to display when asking the user to kill the broker for failover testing. + */ private static final String KILL_BROKER_PROMPT = "Kill broker now, then press Return."; - private String _clientID; - /** Keeps count of the total messages sent purely for debugging purposes. */ + /** + * Keeps count of the total messages sent purely for debugging purposes. + */ private static AtomicInteger numSent = new AtomicInteger(); /** @@ -480,23 +622,20 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * for details. This constructor creates a connection to the broker and creates producer and consumer sessions on * it, to send and recieve its pings and replies on. * - * @param overrides Properties containing any desired overrides to the defaults. - * + * @param overrides Properties containing any desired overrides to the defaults. * @throws Exception Any exceptions are allowed to fall through. */ public PingPongProducer(Properties overrides) throws Exception { - // log.debug("public PingPongProducer(Properties overrides = " + overrides + "): called"); - + // _log.debug("public PingPongProducer(Properties overrides = " + overrides + "): called"); // Create a set of parsed properties from the defaults overriden by the passed in values. ParsedProperties properties = new ParsedProperties(defaults); properties.putAll(overrides); - // Extract the configuration properties to set the pinger up with. - _brokerDetails = properties.getProperty(BROKER_PROPNAME); + _factoryName = properties.getProperty(FACTORY_NAME_PROPNAME); + _fileProperties = properties.getProperty(FILE_PROPERTIES_PROPNAME); _username = properties.getProperty(USERNAME_PROPNAME); _password = properties.getProperty(PASSWORD_PROPNAME); - _virtualpath = properties.getProperty(VIRTUAL_HOST_PROPNAME); _destinationName = properties.getProperty(PING_QUEUE_NAME_PROPNAME); _selector = properties.getProperty(SELECTOR_PROPNAME); _transacted = properties.getPropertyAsBoolean(TRANSACTED_PROPNAME); @@ -515,26 +654,20 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti _rate = properties.getPropertyAsInteger(RATE_PROPNAME); _isPubSub = properties.getPropertyAsBoolean(PUBSUB_PROPNAME); _isUnique = properties.getPropertyAsBoolean(UNIQUE_DESTS_PROPNAME); - _isDurable = properties.getPropertyAsBoolean(DURABLE_DESTS_PROPNAME); _ackMode = properties.getPropertyAsInteger(ACK_MODE_PROPNAME); _consAckMode = properties.getPropertyAsInteger(CONSUMER_ACK_MODE_PROPNAME); _maxPendingSize = properties.getPropertyAsInteger(MAX_PENDING_PROPNAME); - // Check that one or more destinations were specified. if (_noOfDestinations < 1) { throw new IllegalArgumentException("There must be at least one destination."); } - // Set up a throttle to control the send rate, if a rate > 0 is specified. if (_rate > 0) { _rateLimiter = new BatchedThrottle(); _rateLimiter.setRate(_rate); } - - // Create the connection and message producers/consumers. - // establishConnection(true, true); } /** @@ -543,33 +676,32 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * * @param producer Flag to indicate whether or not the producer should be set up. * @param consumer Flag to indicate whether or not the consumers should be set up. - * * @throws Exception Any exceptions are allowed to fall through. */ public void establishConnection(boolean producer, boolean consumer) throws Exception { - // log.debug("public void establishConnection(): called"); + // _log.debug("public void establishConnection(): called"); // Generate a unique identifying name for this client, based on it ip address and the current time. InetAddress address = InetAddress.getLocalHost(); - _clientID = address.getHostName() + System.currentTimeMillis(); + String _clientID = address.getHostName() + System.currentTimeMillis(); // Create a connection to the broker. createConnection(_clientID); // Create transactional or non-transactional sessions, based on the command line arguments. - _producerSession = (Session) _connection.createSession(_transacted, _ackMode); + _producerSession = _connection.createSession(_transacted, _ackMode); _consumerSession = new Session[_noOfConsumers]; for (int i = 0; i < _noOfConsumers; i++) { - _consumerSession[i] = (Session) _consumerConnection[i].createSession(_consTransacted, _consAckMode); + _consumerSession[i] = _consumerConnection[i].createSession(_consTransacted, _consAckMode); } // Create the destinations to send pings to and receive replies from. _replyDestination = _consumerSession[0].createTemporaryQueue(); - createPingDestinations(_noOfDestinations, _selector, _destinationName, _isUnique, _isDurable); + createPingDestinations(_noOfDestinations, _selector, _destinationName); // Create the message producer only if instructed to. if (producer) @@ -589,25 +721,24 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * created with. * * @param clientID The clients identifier. - * - * @throws AMQException Any underlying exceptions are allowed to fall through. - * @throws URLSyntaxException Any underlying exceptions are allowed to fall through. + * @throws Exception Any underlying exceptions are allowed to fall through. */ - protected void createConnection(String clientID) throws AMQException, URLSyntaxException + protected void createConnection(String clientID) throws Exception { - // log.debug("protected void createConnection(String clientID = " + clientID + "): called"); + // _log.debug("protected void createConnection(String clientID = " + clientID + "): called"); - // log.debug("Creating a connection for the message producer."); + // _log.debug("Creating a connection for the message producer."); + Context context = InitialContextHelper.getInitialContext(_fileProperties); + ConnectionFactory factory = (ConnectionFactory) context.lookup(_factoryName); + _connection = factory.createConnection(_username, _password); - _connection = new AMQConnection(_brokerDetails, _username, _password, clientID, _virtualpath); - - // log.debug("Creating " + _noOfConsumers + " connections for the consumers."); + // _log.debug("Creating " + _noOfConsumers + " connections for the consumers."); _consumerConnection = new Connection[_noOfConsumers]; for (int i = 0; i < _noOfConsumers; i++) { - _consumerConnection[i] = new AMQConnection(_brokerDetails, _username, _password, clientID, _virtualpath); + _consumerConnection[i] = factory.createConnection(_username, _password); } } @@ -621,8 +752,8 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti { try { - Properties options = - CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); + Properties options = CommandLineParser + .processCommandLine(args, new CommandLineParser(new String[][]{}), System.getProperties()); // Create a ping producer overriding its defaults with all options passed on the command line. PingPongProducer pingProducer = new PingPongProducer(options); @@ -645,7 +776,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti catch (Exception e) { System.err.println(e.getMessage()); - log.error("Top level handler caught execption.", e); + _log.error("Top level handler caught execption.", e); System.exit(1); } } @@ -664,7 +795,9 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti Thread.sleep(sleepTime); } catch (InterruptedException ie) - { } + { + // do nothing + } } } @@ -676,12 +809,12 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ public List getReplyDestinations() { - // log.debug("public List getReplyDestinations(): called"); + // _log.debug("public List getReplyDestinations(): called"); List replyDestinations = new ArrayList(); replyDestinations.add(_replyDestination); - // log.debug("replyDestinations = " + replyDestinations); + // _log.debug("replyDestinations = " + replyDestinations); return replyDestinations; } @@ -694,84 +827,58 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ public void createProducer() throws JMSException { - // log.debug("public void createProducer(): called"); - - _producer = (MessageProducer) _producerSession.createProducer(null); + _producer = _producerSession.createProducer(null); _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - - // log.debug("Created producer for " + (_persistent ? "persistent" : "non-persistent") + " messages."); + if (_log.isDebugEnabled()) + { + _log.debug("Created producer for " + (_persistent ? "persistent" : "non-persistent") + " messages."); + } } /** * Creates consumers for the specified number of destinations. The destinations themselves are also created by this * method. * - * @param noOfDestinations The number of destinations to create consumers for. - * @param selector The message selector to filter the consumers with. - * @param rootName The root of the name, or actual name if only one is being created. - * @param unique true to make the destinations unique to this pinger, false to share the - * numbering with all pingers on the same JVM. - * + * @param noOfDestinations The number of destinations to create consumers for. + * @param selector The message selector to filter the consumers with. + * @param rootName The root of the name, or actual name if only one is being created. * @throws JMSException Any JMSExceptions are allowed to fall through. */ - public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique, - boolean durable) throws JMSException, AMQException + public void createPingDestinations(int noOfDestinations, String selector, String rootName) throws JMSException { - /*log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " - + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = " - + durable + "): called");*/ - + if (_log.isDebugEnabled()) + { + _log.debug( + "public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " + selector + ", String rootName = " + rootName); + } _pingDestinations = new ArrayList(); - // Create the desired number of ping destinations and consumers for them. - // log.debug("Creating " + noOfDestinations + " destinations to ping."); - + if (_log.isDebugEnabled()) + { + _log.debug("Creating " + noOfDestinations + " destinations to ping."); + } + String id; for (int i = 0; i < noOfDestinations; i++) { - AMQDestination destination; - - String id; - - // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag. - if (unique) - { - // log.debug("Creating unique destinations."); - id = "_" + _queueJVMSequenceID.incrementAndGet() + "_" + _connection.getClientID(); - } - else - { - // log.debug("Creating shared destinations."); - id = "_" + _queueSharedID.incrementAndGet(); - } - + Destination destination; + id = "_" + _queueSharedID.incrementAndGet(); // Check if this is a pub/sub pinger, in which case create topics. if (_isPubSub) { - if (!durable) + destination = _producerSession.createTopic(rootName + id); + if (_log.isDebugEnabled()) { - destination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id); - // log.debug("Created non-durable topic " + destination); - } - else - { - destination = - AMQTopic.createDurableTopic(new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, rootName + id), - _clientID, (AMQConnection) _connection); - // log.debug("Created durable topic " + destination); + _log.debug("Created topic " + rootName + id); } } // Otherwise this is a p2p pinger, in which case create queues. else { - AMQShortString destinationName = new AMQShortString(rootName + id); - destination = - new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, destinationName, destinationName, false, false, - _isDurable); - ((AMQSession) _producerSession).createQueue(destinationName, false, _isDurable, false); - ((AMQSession) _producerSession).bindQueue(destinationName, destinationName, null, - ExchangeDefaults.DIRECT_EXCHANGE_NAME); - - // log.debug("Created queue " + destination); + destination = _producerSession.createQueue(rootName + id); + if (_log.isDebugEnabled()) + { + _log.debug("Created queue " + rootName + id); + } } // Keep the destination. @@ -784,17 +891,16 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * * @param destinations The destinations to listen to. * @param selector A selector to filter the messages with. - * * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through. */ public void createReplyConsumers(Collection destinations, String selector) throws JMSException { - /*log.debug("public void createReplyConsumers(Collection destinations = " + destinations + /*_log.debug("public void createReplyConsumers(Collection destinations = " + destinations + ", String selector = " + selector + "): called");*/ - // log.debug("There are " + destinations.size() + " destinations."); - // log.debug("Creating " + _noOfConsumers + " consumers on each destination."); - // log.debug("Total number of consumers is: " + (destinations.size() * _noOfConsumers)); + // _log.debug("There are " + destinations.size() + " destinations."); + // _log.debug("Creating " + _noOfConsumers + " consumers on each destination."); + // _log.debug("Total number of consumers is: " + (destinations.size() * _noOfConsumers)); for (Destination destination : destinations) { @@ -803,21 +909,19 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti for (int i = 0; i < _noOfConsumers; i++) { // Create a consumer for the destination and set this pinger to listen to its messages. - _consumer[i] = - _consumerSession[i].createConsumer(destination, PREFETCH_DEFAULT, NO_LOCAL_DEFAULT, EXCLUSIVE_DEFAULT, - selector); + _consumer[i] = _consumerSession[i].createConsumer(destination, selector, NO_LOCAL_DEFAULT); final int consumerNo = i; _consumer[i].setMessageListener(new MessageListener() + { + public void onMessage(Message message) { - public void onMessage(Message message) - { - onMessageWithConsumerNo(message, consumerNo); - } - }); + onMessageWithConsumerNo(message, consumerNo); + } + }); - // log.debug("Set consumer " + i + " to listen to replies sent to destination: " + destination); + // _log.debug("Set consumer " + i + " to listen to replies sent to destination: " + destination); } } } @@ -831,7 +935,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ public void onMessageWithConsumerNo(Message message, int consumerNo) { - // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo = " + consumerNo + "): called"); + // _log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo = " + consumerNo + "): called"); try { long now = System.nanoTime(); @@ -842,13 +946,13 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti // Extract the messages correlation id. String correlationID = message.getJMSCorrelationID(); - // log.debug("correlationID = " + correlationID); + // _log.debug("correlationID = " + correlationID); int num = message.getIntProperty("MSG_NUM"); - // log.info("Message " + num + " received."); + // _log.info("Message " + num + " received."); boolean isRedelivered = message.getJMSRedelivered(); - // log.debug("isRedelivered = " + isRedelivered); + // _log.debug("isRedelivered = " + isRedelivered); if (!isRedelivered) { @@ -862,7 +966,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti // Restart the timeout timer on every message. perCorrelationId.timeOutStart = System.nanoTime(); - // log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); + // _log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); // Decrement the countdown latch. Before this point, it is possible that two threads might enter this // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block @@ -887,7 +991,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti if ((_maxPendingSize > 0) && (unreceivedSize < _maxPendingSize)) // && (_sendPauseBarrier.getNumberWaiting() == 1)) { - // log.debug("unreceived size estimate under limit = " + unreceivedSize); + // _log.debug("unreceived size estimate under limit = " + unreceivedSize); // Wait on the send pause barrier for the limit to be re-established. /*try @@ -908,19 +1012,19 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti // NDC.push("/rem" + remainingCount); - // log.debug("remainingCount = " + remainingCount); - // log.debug("trueCount = " + trueCount); + // _log.debug("remainingCount = " + remainingCount); + // _log.debug("trueCount = " + trueCount); // Commit on transaction batch size boundaries. At this point in time the waiting producer remains // blocked, even on the last message. // Commit count is divided by noOfConsumers in p2p mode, so that each consumer only commits on // each batch boundary. For pub/sub each consumer gets every message so no division is done. long commitCount = _isPubSub ? remainingCount : (remainingCount / _noOfConsumers); - // log.debug("commitCount = " + commitCount); + // _log.debug("commitCount = " + commitCount); if ((commitCount % _txBatchSize) == 0) { - // log.debug("Trying commit for consumer " + consumerNo + "."); + // _log.debug("Trying commit for consumer " + consumerNo + "."); commitTx(_consumerSession[consumerNo]); } @@ -940,12 +1044,12 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti } else { - log.warn("Got unexpected message with correlationId: " + correlationID); + _log.warn("Got unexpected message with correlationId: " + correlationID); } } else { - log.warn("Got redelivered message, ignoring."); + _log.warn("Got redelivered message, ignoring."); } // Print out ping times for every message in verbose mode only. @@ -956,17 +1060,17 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti if (timestamp != null) { long diff = System.nanoTime() - timestamp; - //log.trace("Time for round trip (nanos): " + diff); + //_log.trace("Time for round trip (nanos): " + diff); } }*/ } catch (JMSException e) { - log.warn("There was a JMSException: " + e.getMessage(), e); + _log.warn("There was a JMSException: " + e.getMessage(), e); } finally { - // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo): ending"); + // _log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo): ending"); // NDC.clear(); } } @@ -980,17 +1084,15 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * @param numPings The number of ping messages to send. * @param timeout The timeout in milliseconds. * @param messageCorrelationId The message correlation id. If this is null, one is generated. - * * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait * for all prematurely. - * * @throws JMSException All underlying JMSExceptions are allowed to fall through. * @throws InterruptedException When interrupted by a timeout */ public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) - throws JMSException, InterruptedException + throws JMSException, InterruptedException { - /*log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + /*_log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ // Generate a unique correlation id to put on the messages before sending them, if one was not specified. @@ -1034,31 +1136,31 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti allMessagesReceived = numReplies == getExpectedNumPings(numPings); - // log.debug("numReplies = " + numReplies); - // log.debug("allMessagesReceived = " + allMessagesReceived); + // _log.debug("numReplies = " + numReplies); + // _log.debug("allMessagesReceived = " + allMessagesReceived); // Recheck the timeout condition. long now = System.nanoTime(); long lastMessageReceievedAt = perCorrelationId.timeOutStart; timedOut = (now - lastMessageReceievedAt) > (timeout * 1000000); - // log.debug("now = " + now); - // log.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); + // _log.debug("now = " + now); + // _log.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); } while (!timedOut && !allMessagesReceived); if ((numReplies < getExpectedNumPings(numPings)) && _verbose) { - log.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); + _log.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); } else if (_verbose) { - log.info("Got all replies on id, " + messageCorrelationId); + _log.info("Got all replies on id, " + messageCorrelationId); } // commitTx(_consumerSession); - // log.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); + // _log.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); return numReplies; } @@ -1077,12 +1179,11 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * @param message The message to send. * @param numPings The number of pings to send. * @param messageCorrelationId A correlation id to place on all messages sent. - * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException { - /*log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings + /*_log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ if (message == null) @@ -1112,7 +1213,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti // Spew out per message timings on every message sonly in verbose mode. /*if (_verbose) { - log.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); + _log.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); }*/ } @@ -1131,15 +1232,13 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * * @param i The count of messages sent so far in a loop of multiple calls to this send method. * @param message The message to send. - * * @return true if the messages were committed, false otherwise. - * * @throws JMSException All underlyiung JMSExceptions are allowed to fall through. */ protected boolean sendMessage(int i, Message message) throws JMSException { - // log.debug("protected boolean sendMessage(int i = " + i + ", Message message): called"); - // log.debug("_txBatchSize = " + _txBatchSize); + // _log.debug("protected boolean sendMessage(int i = " + i + ", Message message): called"); + // _log.debug("_txBatchSize = " + _txBatchSize); // Round robin the destinations as the messages are sent. Destination destination = _pingDestinations.get(i % _pingDestinations.size()); @@ -1152,7 +1251,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti _failBeforeSend = false; } - // log.trace("Failing Before Send"); + // _log.trace("Failing Before Send"); waitForUser(KILL_BROKER_PROMPT); } @@ -1167,7 +1266,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti if (unreceivedSize > _maxPendingSize) { - // log.debug("unreceived size estimate over limit = " + unreceivedSize); + // _log.debug("unreceived size estimate over limit = " + unreceivedSize); // Wait on the send pause barrier for the limit to be re-established. try @@ -1200,7 +1299,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti message.setIntProperty("MSG_NUM", num); setTimestamp(message); _producer.send(message); - // log.info("Message " + num + " sent."); + // _log.info("Message " + num + " sent."); } else { @@ -1208,7 +1307,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti message.setIntProperty("MSG_NUM", num); setTimestamp(message); _producer.send(destination, message); - // log.info("Message " + num + " sent."); + // _log.info("Message " + num + " sent."); } // Increase the unreceived size, this may actually happen aftern the message is recevied. @@ -1226,7 +1325,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti // Commit on every transaction batch size boundary. Here i + 1 is the count of actual messages sent. if (((i + 1) % _txBatchSize) == 0) { - // log.debug("Trying commit on producer session."); + // _log.debug("Trying commit on producer session."); committed = commitTx(_producerSession); } @@ -1252,12 +1351,12 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti catch (JMSException e) { _publish = false; - // log.debug("There was a JMSException: " + e.getMessage(), e); + // _log.debug("There was a JMSException: " + e.getMessage(), e); } catch (InterruptedException e) { _publish = false; - // log.debug("There was an interruption: " + e.getMessage(), e); + // _log.debug("There was an interruption: " + e.getMessage(), e); } } @@ -1272,7 +1371,9 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti _chainedMessageListener = messageListener; } - /** Removes any chained message listeners from this pinger. */ + /** + * Removes any chained message listeners from this pinger. + */ public void removeChainedMessageListener() { _chainedMessageListener = null; @@ -1284,9 +1385,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * @param replyQueue The reply-to destination for the message. * @param messageSize The desired size of the message in bytes. * @param persistent true if the message should use persistent delivery, false otherwise. - * * @return A freshly generated test message. - * * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. */ public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException @@ -1302,29 +1401,12 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti protected void setTimestamp(Message msg) throws JMSException { - if (((AMQSession) _producerSession).isStrictAMQP()) - { - ((AMQMessage) msg).setTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME), System.nanoTime()); - } - else - { - msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); - } + msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); } protected long getTimestamp(Message msg) throws JMSException { - - if (((AMQSession) _producerSession).isStrictAMQP()) - { - Long value = ((AMQMessage) msg).getTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME)); - - return (value == null) ? 0L : value; - } - else - { - return msg.getLongProperty(PingPongProducer.MESSAGE_TIMESTAMP_PROPNAME); - } + return msg.getLongProperty(PingPongProducer.MESSAGE_TIMESTAMP_PROPNAME); } /** @@ -1346,7 +1428,9 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti } } - /** Implements a ping loop that repeatedly pings until the publish flag becomes false. */ + /** + * Implements a ping loop that repeatedly pings until the publish flag becomes false. + */ public void run() { // Keep running until the publish flag is cleared. @@ -1364,7 +1448,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ public void onException(JMSException e) { - // log.debug("public void onException(JMSException e = " + e + "): called", e); + // _log.debug("public void onException(JMSException e = " + e + "): called", e); _publish = false; } @@ -1377,12 +1461,12 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti public Thread getShutdownHook() { return new Thread(new Runnable() - { - public void run() - { - stop(); - } - }); + { + public void run() + { + stop(); + } + }); } /** @@ -1392,14 +1476,14 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ public void close() throws JMSException { - // log.debug("public void close(): called"); + // _log.debug("public void close(): called"); try { if (_connection != null) { _connection.close(); - // log.debug("Close connection."); + // _log.debug("Close connection."); } for (int i = 0; i < _noOfConsumers; i++) @@ -1407,7 +1491,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti if (_consumerConnection[i] != null) { _consumerConnection[i].close(); - // log.debug("Closed consumer connection."); + // _log.debug("Closed consumer connection."); } } } @@ -1427,46 +1511,43 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti /** * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not a * transactional controlSession, this method does nothing (unless the failover after send flag is set). - * + *

    *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit is * applied. This flag applies whether the pinger is transactional or not. - * + *

    *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the commit * is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker after the * commit is applied. These flags will only apply if using a transactional pinger. * * @param session The controlSession to commit - * * @return true if the controlSession was committed, false if it was not. - * * @throws javax.jms.JMSException If the commit fails and then the rollback fails. - * * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit * method, because commits only apply to transactional pingers, but fail after send applied to transactional and * non-transactional alike. */ protected boolean commitTx(Session session) throws JMSException { - // log.debug("protected void commitTx(Session session): called"); + // _log.debug("protected void commitTx(Session session): called"); boolean committed = false; - // log.trace("Batch time reached"); + // _log.trace("Batch time reached"); if (_failAfterSend) { - // log.trace("Batch size reached"); + // _log.trace("Batch size reached"); if (_failOnce) { _failAfterSend = false; } - // log.trace("Failing After Send"); + // _log.trace("Failing After Send"); waitForUser(KILL_BROKER_PROMPT); } if (session.getTransacted()) { - // log.debug("Session is transacted."); + // _log.debug("Session is transacted."); try { @@ -1477,14 +1558,14 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti _failBeforeCommit = false; } - // log.trace("Failing Before Commit"); + // _log.trace("Failing Before Commit"); waitForUser(KILL_BROKER_PROMPT); } long start = System.nanoTime(); session.commit(); committed = true; - // log.debug("Time taken to commit :" + ((System.nanoTime() - start) / 1000000f) + " ms"); + // _log.debug("Time taken to commit :" + ((System.nanoTime() - start) / 1000000f) + " ms"); if (_failAfterCommit) { @@ -1493,30 +1574,23 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti _failAfterCommit = false; } - // log.trace("Failing After Commit"); + // _log.trace("Failing After Commit"); waitForUser(KILL_BROKER_PROMPT); } - // log.debug("Session Commited."); + // _log.debug("Session Commited."); } catch (JMSException e) { - // log.debug("JMSException on commit:" + e.getMessage(), e); - - // Warn that the bounce back client is not available. - if (e.getLinkedException() instanceof AMQNoConsumersException) - { - // log.debug("No consumers on queue."); - } - + // _log.debug("JMSException on commit:" + e.getMessage(), e); try { session.rollback(); - // log.debug("Message rolled back."); + // _log.debug("Message rolled back."); } catch (JMSException jmse) { - // log.debug("JMSE on rollback:" + jmse.getMessage(), jmse); + // _log.debug("JMSE on rollback:" + jmse.getMessage(), jmse); // Both commit and rollback failed. Throw the rollback exception. throw jmse; @@ -1562,14 +1636,13 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * Calculates how many pings are expected to be received for the given number sent. * * @param numpings The number of pings that will be sent. - * * @return The number that should be received, for the test to pass. */ public int getExpectedNumPings(int numpings) { - // log.debug("public int getExpectedNumPings(int numpings = " + numpings + "): called"); + // _log.debug("public int getExpectedNumPings(int numpings = " + numpings + "): called"); - // log.debug("Each ping will be received by " + (_isPubSub ? getConsumersPerDestination() : 1) + " consumers."); + // _log.debug("Each ping will be received by " + (_isPubSub ? getConsumersPerDestination() : 1) + " consumers."); return numpings * (_isPubSub ? getConsumersPerDestination() : 1); } @@ -1579,7 +1652,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * PingPongProducer#onMessageWithConsumerNo} method is called, the chained listener set through the {@link * PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected count of * messages with that correlation id. - * + *

    *

    Provided only one pinger is producing messages with that correlation id, the chained listener will always be * given unique message counts. It will always be called while the producer waiting for all messages to arrive is * still blocked. @@ -1593,7 +1666,6 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * @param message The newly arrived message. * @param remainingCount The number of messages left to complete the test. * @param latency The nanosecond latency of the message. - * * @throws JMSException Any JMS exceptions is allowed to fall through. */ public void onMessage(Message message, int remainingCount, long latency) throws JMSException; @@ -1605,10 +1677,14 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ protected static class PerCorrelationId { - /** Holds a countdown on number of expected messages. */ + /** + * Holds a countdown on number of expected messages. + */ CountDownLatch trafficLight; - /** Holds the last timestamp that the timeout was reset to. */ + /** + * Holds the last timestamp that the timeout was reset to. + */ Long timeOutStart; } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java index f289fe0db2..780589768f 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java @@ -172,10 +172,10 @@ public class PingPongTestPerf extends AsymptoticTestCase PerThreadSetup perThreadSetup = new PerThreadSetup(); // Extract the test set up paramaeters. - String brokerDetails = testParameters.getProperty(PingPongProducer.BROKER_PROPNAME); + String fileProperties = testParameters.getProperty(PingPongProducer.FILE_PROPERTIES_PROPNAME); + String factoryName = testParameters.getProperty(PingPongProducer.FACTORY_NAME_PROPNAME); String username = testParameters.getProperty(PingPongProducer.USERNAME_PROPNAME); String password = testParameters.getProperty(PingPongProducer.PASSWORD_PROPNAME); - String virtualPath = testParameters.getProperty(PingPongProducer.VIRTUAL_HOST_PROPNAME); String destinationName = testParameters.getProperty(PingPongProducer.PING_QUEUE_NAME_PROPNAME); boolean persistent = testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME); boolean transacted = testParameters.getPropertyAsBoolean(PingPongProducer.TRANSACTED_PROPNAME); @@ -187,7 +187,7 @@ public class PingPongTestPerf extends AsymptoticTestCase { // Establish a bounce back client on the ping queue to bounce back the pings. perThreadSetup._testPingBouncer = - new PingPongBouncer(brokerDetails, username, password, virtualPath, destinationName, persistent, + new PingPongBouncer(fileProperties, factoryName, username, password, destinationName, persistent, transacted, selector, verbose, pubsub); // Start the connections for client and producer running. diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java deleted file mode 100644 index d5c0979399..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * - * 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.qpid.topic; - -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.config.ConnectorConfig; -import org.apache.qpid.config.Connector; -import org.apache.qpid.config.AbstractConfig; - -import javax.jms.Connection; - -public class Config extends AbstractConfig implements ConnectorConfig -{ - - private String host = "localhost"; - private int port = 5672; - private String factory = null; - - private int payload = 256; - private int messages = 1000; - private int clients = 1; - private int batch = 1; - private long delay = 1; - private int warmup; - private int ackMode= AMQSession.NO_ACKNOWLEDGE; - private String clientId; - private String subscriptionId; - private String selector; - private String destinationName; - private boolean persistent; - private boolean transacted; - private int destinationsCount; - private int batchSize; - private int rate; - private boolean ispubsub; - private long timeout; - - public Config() - { - } - - public int getAckMode() - { - return ackMode; - } - - public void setPayload(int payload) - { - this.payload = payload; - } - - public int getPayload() - { - return payload; - } - - void setClients(int clients) - { - this.clients = clients; - } - - int getClients() - { - return clients; - } - - void setMessages(int messages) - { - this.messages = messages; - } - - public int getMessages() - { - return messages; - } - - public int getBatchSize() - { - return batchSize; - } - - public int getRate() - { - return rate; - } - - public int getDestinationsCount() - { - return destinationsCount; - } - - public String getHost() - { - return host; - } - - public void setHost(String host) - { - this.host = host; - } - - public int getPort() - { - return port; - } - - public String getFactory() - { - return factory; - } - - public void setPort(int port) - { - this.port = port; - } - - int getBatch() - { - return batch; - } - - void setBatch(int batch) - { - this.batch = batch; - } - - int getWarmup() - { - return warmup; - } - - void setWarmup(int warmup) - { - this.warmup = warmup; - } - - public long getDelay() - { - return delay; - } - - public void setDelay(long delay) - { - this.delay = delay; - } - - public long getTimeout() - { - return timeout; - } - - public void setTimeout(long time) - { - this.timeout = time; - } - - public String getClientId() - { - return clientId; - } - - public String getSubscriptionId() - { - return subscriptionId; - } - - public String getSelector() - { - return selector; - } - - public String getDestination() - { - return destinationName; - } - - public boolean usePersistentMessages() - { - return persistent; - } - - public boolean isTransacted() - { - return transacted; - } - - public boolean isPubSub() - { - return ispubsub; - } - - public void setOption(String key, String value) - { - if("-host".equalsIgnoreCase(key)) - { - setHost(value); - } - else if("-port".equalsIgnoreCase(key)) - { - try - { - setPort(Integer.parseInt(value)); - } - catch(NumberFormatException e) - { - throw new RuntimeException("Bad port number: " + value, e); - } - } - else if("-payload".equalsIgnoreCase(key)) - { - setPayload(parseInt("Bad payload size", value)); - } - else if("-messages".equalsIgnoreCase(key)) - { - setMessages(parseInt("Bad message count", value)); - } - else if("-clients".equalsIgnoreCase(key)) - { - setClients(parseInt("Bad client count", value)); - } - else if("-batch".equalsIgnoreCase(key)) - { - setBatch(parseInt("Bad batch count", value)); - } - else if("-delay".equalsIgnoreCase(key)) - { - setDelay(parseLong("Bad batch delay", value)); - } - else if("-warmup".equalsIgnoreCase(key)) - { - setWarmup(parseInt("Bad warmup count", value)); - } - else if("-ack".equalsIgnoreCase(key)) - { - ackMode = parseInt("Bad ack mode", value); - } - else if("-factory".equalsIgnoreCase(key)) - { - factory = value; - } - else if("-clientId".equalsIgnoreCase(key)) - { - clientId = value; - } - else if("-subscriptionId".equalsIgnoreCase(key)) - { - subscriptionId = value; - } - else if("-persistent".equalsIgnoreCase(key)) - { - persistent = "true".equalsIgnoreCase(value); - } - else if("-transacted".equalsIgnoreCase(key)) - { - transacted = "true".equalsIgnoreCase(value); - } - else if ("-destinationscount".equalsIgnoreCase(key)) - { - destinationsCount = parseInt("Bad destinations count", value); - } - else if ("-batchsize".equalsIgnoreCase(key)) - { - batchSize = parseInt("Bad batch size", value); - } - else if ("-rate".equalsIgnoreCase(key)) - { - rate = parseInt("MEssage rate", value); - } - else if("-pubsub".equalsIgnoreCase(key)) - { - ispubsub = "true".equalsIgnoreCase(value); - } - else if("-selector".equalsIgnoreCase(key)) - { - selector = value; - } - else if("-destinationname".equalsIgnoreCase(key)) - { - destinationName = value; - } - else if("-timeout".equalsIgnoreCase(key)) - { - setTimeout(parseLong("Bad timeout data", value)); - } - else - { - System.out.println("Ignoring unrecognised option: " + key); - } - } - - static String getAckModeDescription(int ackMode) - { - switch(ackMode) - { - case AMQSession.NO_ACKNOWLEDGE: return "NO_ACKNOWLEDGE"; - case AMQSession.AUTO_ACKNOWLEDGE: return "AUTO_ACKNOWLEDGE"; - case AMQSession.CLIENT_ACKNOWLEDGE: return "CLIENT_ACKNOWLEDGE"; - case AMQSession.DUPS_OK_ACKNOWLEDGE: return "DUPS_OK_ACKNOWELDGE"; - case AMQSession.PRE_ACKNOWLEDGE: return "PRE_ACKNOWLEDGE"; - } - return "AckMode=" + ackMode; - } - - public Connection createConnection() throws Exception - { - return new Connector().createConnection(this); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java deleted file mode 100644 index 6dcea42bfe..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * - * 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.qpid.topic; - -import java.util.Random; - -import javax.jms.*; - -import org.apache.log4j.Logger; -import org.apache.log4j.NDC; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.exchange.ExchangeDefaults; - -/** - * This class has not kept up to date with the topic_listener in the cpp tests. It should provide identical behaviour for - * cross testing the java and cpp clients. - * - *

    How the cpp topic_publisher operates: - * It publishes text messages to the default topic exchange, on virtual host "/test", on the topic "topic_control", for - * the specified number of test messages to be sent. - * It publishes a report request message (on same topic), with the header text field "TYPE", value "REPORT_REQUEST", - * optionally within a transaction, and waits for the specified number of consumers to reply to this request. The - * listeners should reply to this message on a queue named "response", on virtual host "/test", with some sort of message - * about the number of messages received and how long it took, although the publisher never looks at the message content. - * The publisher then send a message (on the same topic), with the header text field "TYPE", value "TERMINATION_REQUEST", - * which the listener should close its connection and terminate upon receipt of. - * - * @todo I've added lots of field table types in the report message, just to check if the other end can decode them - * correctly. Not really the right place to test this, so remove them from - * {@link #createReportResponseMessage(String)} once a better test exists. - */ -public class Listener implements MessageListener -{ - private static Logger log = Logger.getLogger(Listener.class); - - public static final String CONTROL_TOPIC = "topic_control"; - public static final String RESPONSE_QUEUE = "response"; - - private final Topic _topic; - //private final Topic _control; - - private final Queue _response; - - /** Holds the connection to listen on. */ - private final Connection _connection; - - /** Holds the producer to send control messages on. */ - private final MessageProducer _controller; - - /** Holds the JMS session. */ - private final javax.jms.Session _session; - - /** Holds a flag to indicate that a timer has begun on the first message. Reset when report is sent. */ - private boolean init; - - /** Holds the count of messages received by this listener. */ - private int count; - - /** Used to hold the start time of the first message. */ - private long start; - private static String clientId; - - Listener(Connection connection, int ackMode, String name) throws Exception - { - log.debug("Listener(Connection connection = " + connection + ", int ackMode = " + ackMode + ", String name = " + name - + "): called"); - - _connection = connection; - _session = connection.createSession(false, ackMode); - - if (_session instanceof AMQSession) - { - _topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, CONTROL_TOPIC); - //_control = new AMQTopic(CONTROL_TOPIC); - _response = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, RESPONSE_QUEUE); - } - else - { - _topic = _session.createTopic(CONTROL_TOPIC); - //_control = _session.createTopic(CONTROL_TOPIC); - _response = _session.createQueue(RESPONSE_QUEUE); - } - - //register for events - if (name == null) - { - log.debug("Calling _factory.createTopicConsumer().setMessageListener(this)"); - createTopicConsumer().setMessageListener(this); - } - else - { - log.debug("Calling createDurableTopicConsumer(name).setMessageListener(this)"); - createDurableTopicConsumer(name).setMessageListener(this); - } - - _connection.start(); - - _controller = createControlPublisher(); - System.out.println("Waiting for messages " + Config.getAckModeDescription(ackMode) - + - ((name == null) - ? "" : (" (subscribed with name " + name + " and client id " + connection.getClientID() + ")")) - + "..."); - } - - public static void main(String[] argv) throws Exception - { - clientId = "Listener-" + System.currentTimeMillis(); - - NDC.push(clientId); - - Config config = new Config(); - config.setOptions(argv); - - //Connection con = config.createConnection(); - Connection con = - new AMQConnection("amqp://guest:guest@testid/test?brokerlist='" + config.getHost() + ":" + config.getPort() - + "'"); - - if (config.getClientId() != null) - { - con.setClientID(config.getClientId()); - } - - new Listener(con, config.getAckMode(), config.getSubscriptionId()); - - NDC.pop(); - NDC.remove(); - } - - /** - * Checks whether or not a text field on a message has the specified value. - * - * @param m The message to check. - * @param fieldName The name of the field to check. - * @param value The expected value of the field to compare with. - * - * @return trueIf the specified field has the specified value, fals otherwise. - * - * @throws JMSException Any JMSExceptions are allowed to fall through. - */ - private static boolean checkTextField(Message m, String fieldName, String value) throws JMSException - { - log.debug("private static boolean checkTextField(Message m = " + m + ", String fieldName = " + fieldName - + ", String value = " + value + "): called"); - - String comp = m.getStringProperty(fieldName); - log.debug("comp = " + comp); - - boolean result = (comp != null) && comp.equals(value); - log.debug("result = " + result); - - return result; - } - - public void onMessage(Message message) - { - NDC.push(clientId); - - log.debug("public void onMessage(Message message = " + message + "): called"); - - if (!init) - { - start = System.nanoTime() / 1000000; - count = 0; - init = true; - } - - try - { - if (isShutdown(message)) - { - log.debug("Got a shutdown message."); - shutdown(); - } - else if (isReport(message)) - { - log.debug("Got a report request message."); - - // Send the report. - report(); - init = false; - } - } - catch (JMSException e) - { - log.warn("There was a JMSException during onMessage.", e); - } - finally - { - NDC.pop(); - } - } - - Message createReportResponseMessage(String msg) throws JMSException - { - Message message = _session.createTextMessage(msg); - - // Shove some more field table type in the message just to see if the other end can handle it. - message.setBooleanProperty("BOOLEAN", true); - message.setByteProperty("BYTE", (byte) 5); - message.setDoubleProperty("DOUBLE", Math.PI); - message.setFloatProperty("FLOAT", 1.0f); - message.setIntProperty("INT", 1); - message.setShortProperty("SHORT", (short) 1); - message.setLongProperty("LONG", (long) 1827361278); - message.setStringProperty("STRING", "hello"); - - return message; - } - - boolean isShutdown(Message m) throws JMSException - { - boolean result = checkTextField(m, "TYPE", "TERMINATION_REQUEST"); - - //log.debug("isShutdown = " + result); - - return result; - } - - boolean isReport(Message m) throws JMSException - { - boolean result = checkTextField(m, "TYPE", "REPORT_REQUEST"); - - //log.debug("isReport = " + result); - - return result; - } - - MessageConsumer createTopicConsumer() throws Exception - { - return _session.createConsumer(_topic); - } - - MessageConsumer createDurableTopicConsumer(String name) throws Exception - { - return _session.createDurableSubscriber(_topic, name); - } - - MessageProducer createControlPublisher() throws Exception - { - return _session.createProducer(_response); - } - - private void shutdown() - { - try - { - _session.close(); - _connection.stop(); - _connection.close(); - } - catch (Exception e) - { - e.printStackTrace(System.out); - } - } - - private void report() - { - log.debug("private void report(): called"); - - try - { - String msg = getReport(); - _controller.send(createReportResponseMessage(msg)); - log.debug("Sent report: " + msg); - } - catch (Exception e) - { - e.printStackTrace(System.out); - } - } - - private String getReport() - { - long time = ((System.nanoTime() / 1000000) - start); - - return "Received " + count + " in " + time + "ms"; - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java deleted file mode 100644 index 4efdc1cb56..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * - * 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.qpid.topic; - -import javax.jms.*; - -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.exchange.ExchangeDefaults; - -/** - */ -class MessageFactory -{ - private static final char[] DATA = "abcdefghijklmnopqrstuvwxyz".toCharArray(); - - private final Session _session; - private final Topic _topic; - private final Topic _control; - private final byte[] _payload; - - MessageFactory(Session session) throws JMSException - { - this(session, 256); - } - - MessageFactory(Session session, int size) throws JMSException - { - _session = session; - if (session instanceof AMQSession) - { - _topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, "topic_control"); - _control = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, "topictest.control"); - } - else - { - _topic = session.createTopic("topic_control"); - _control = session.createTopic("topictest.control"); - } - - _payload = new byte[size]; - - for (int i = 0; i < size; i++) - { - _payload[i] = (byte) DATA[i % DATA.length]; - } - } - - private static boolean checkText(Message m, String s) - { - try - { - return (m instanceof TextMessage) && ((TextMessage) m).getText().equals(s); - } - catch (JMSException e) - { - e.printStackTrace(System.out); - - return false; - } - } - - Topic getTopic() - { - return _topic; - } - - Message createEventMessage() throws JMSException - { - BytesMessage msg = _session.createBytesMessage(); - msg.writeBytes(_payload); - - return msg; - } - - Message createShutdownMessage() throws JMSException - { - return _session.createTextMessage("SHUTDOWN"); - } - - Message createReportRequestMessage() throws JMSException - { - return _session.createTextMessage("REPORT"); - } - - Message createReportResponseMessage(String msg) throws JMSException - { - return _session.createTextMessage(msg); - } - - boolean isShutdown(Message m) - { - return checkText(m, "SHUTDOWN"); - } - - boolean isReport(Message m) - { - return checkText(m, "REPORT"); - } - - Object getReport(Message m) - { - try - { - return ((TextMessage) m).getText(); - } - catch (JMSException e) - { - e.printStackTrace(System.out); - - return e.toString(); - } - } - - MessageConsumer createTopicConsumer() throws Exception - { - return _session.createConsumer(_topic); - } - - MessageConsumer createDurableTopicConsumer(String name) throws Exception - { - return _session.createDurableSubscriber(_topic, name); - } - - MessageConsumer createControlConsumer() throws Exception - { - return _session.createConsumer(_control); - } - - MessageProducer createTopicPublisher() throws Exception - { - return _session.createProducer(_topic); - } - - MessageProducer createControlPublisher() throws Exception - { - return _session.createProducer(_control); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java deleted file mode 100644 index c3b19b558a..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * - * 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.qpid.topic; - -import javax.jms.*; - -public class Publisher implements MessageListener -{ - private final Object _lock = new Object(); - private final Connection _connection; - private final Session _session; - private final MessageFactory _factory; - private final MessageProducer _publisher; - private int _count; - - Publisher(Connection connection, int size, int ackMode, boolean persistent) throws Exception - { - _connection = connection; - _session = _connection.createSession(false, ackMode); - _factory = new MessageFactory(_session, size); - _publisher = _factory.createTopicPublisher(); - _publisher.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - System.out.println("Publishing " + (persistent ? "persistent" : "non-persistent") + " messages of " + size + " bytes, " + Config.getAckModeDescription(ackMode) + "."); - } - - private void test(Config config) throws Exception - { - test(config.getBatch(), config.getDelay(), config.getMessages(), config.getClients(), config.getWarmup()); - } - - private void test(int batches, long delay, int msgCount, int consumerCount, int warmup) throws Exception - { - _factory.createControlConsumer().setMessageListener(this); - _connection.start(); - - if (warmup > 0) - { - System.out.println("Runing warmup (" + warmup + " msgs)"); - long time = batch(warmup, consumerCount); - System.out.println("Warmup completed in " + time + "ms"); - } - - long[] times = new long[batches]; - for (int i = 0; i < batches; i++) - { - if (i > 0) - { - Thread.sleep(delay * 1000); - } - times[i] = batch(msgCount, consumerCount); - System.out.println("Batch " + (i + 1) + " of " + batches + " completed in " + times[i] + " ms."); - } - - long min = min(times); - long max = max(times); - System.out.println("min: " + min + ", max: " + max + " avg: " + avg(times, min, max)); - - //request shutdown - _publisher.send(_factory.createShutdownMessage()); - - _connection.stop(); - _connection.close(); - } - - private long batch(int msgCount, int consumerCount) throws Exception - { - _count = consumerCount; - long start = System.currentTimeMillis(); - publish(msgCount); - waitForCompletion(consumerCount); - return System.currentTimeMillis() - start; - } - - private void publish(int count) throws Exception - { - - //send events - for (int i = 0; i < count; i++) - { - _publisher.send(_factory.createEventMessage()); - if ((i + 1) % 100 == 0) - { - System.out.println("Sent " + (i + 1) + " messages"); - } - } - - //request report - _publisher.send(_factory.createReportRequestMessage()); - } - - private void waitForCompletion(int consumers) throws Exception - { - System.out.println("Waiting for completion..."); - synchronized (_lock) - { - while (_count > 0) - { - _lock.wait(); - } - } - } - - - public void onMessage(Message message) - { - System.out.println("Received report " + _factory.getReport(message) + " " + --_count + " remaining"); - if (_count == 0) - { - synchronized (_lock) - { - _lock.notify(); - } - } - } - - static long min(long[] times) - { - long min = times.length > 0 ? times[0] : 0; - for (int i = 0; i < times.length; i++) - { - min = Math.min(min, times[i]); - } - return min; - } - - static long max(long[] times) - { - long max = times.length > 0 ? times[0] : 0; - for (int i = 0; i < times.length; i++) - { - max = Math.max(max, times[i]); - } - return max; - } - - static long avg(long[] times, long min, long max) - { - long sum = 0; - for (int i = 0; i < times.length; i++) - { - sum += times[i]; - } - - int adjustment = 0; - - // Remove min and max if we have run enough batches. - if (times.length > 2) - { - sum -= min; - sum -= max; - adjustment = 2; - } - - return (sum / (times.length - adjustment)); - } - - public static void main(String[] argv) throws Exception - { - Config config = new Config(); - config.setOptions(argv); - - Connection con = config.createConnection(); - int size = config.getPayload(); - int ackMode = config.getAckMode(); - boolean persistent = config.usePersistentMessages(); - new Publisher(con, size, ackMode, persistent).test(config); - } -} -- cgit v1.2.1 From bf3d29992373c4c0c02acb1be3e83918a0f0e9e0 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Fri, 24 Aug 2007 19:02:23 +0000 Subject: Fixed compilation errors related to PingPongBouncer. It looks like this file was accidently deleted. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@569480 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/requestreply/PingPongTestPerf.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java index 780589768f..a6b74911e1 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java @@ -186,12 +186,12 @@ public class PingPongTestPerf extends AsymptoticTestCase synchronized (this) { // Establish a bounce back client on the ping queue to bounce back the pings. - perThreadSetup._testPingBouncer = + /* perThreadSetup._testPingBouncer = new PingPongBouncer(fileProperties, factoryName, username, password, destinationName, persistent, transacted, selector, verbose, pubsub); // Start the connections for client and producer running. - perThreadSetup._testPingBouncer.getConnection().start(); + perThreadSetup._testPingBouncer.getConnection().start();*/ // Establish a ping-pong client on the ping queue to send the pings and receive replies with. perThreadSetup._testPingProducer = new PingPongProducer(testParameters); @@ -246,6 +246,6 @@ public class PingPongTestPerf extends AsymptoticTestCase /** * Holds the test ping client. */ - private PingPongBouncer _testPingBouncer; + //private PingPongBouncer _testPingBouncer; } } -- cgit v1.2.1 From 2a04e1467bc3f544933e342c2af456ef8519f297 Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Sat, 25 Aug 2007 15:33:32 +0000 Subject: added bouncer git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@569689 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/requestreply/PingPongBouncer.java | 392 +++++++++++++++++++++ .../apache/qpid/requestreply/PingPongTestPerf.java | 6 +- 2 files changed, 395 insertions(+), 3 deletions(-) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java new file mode 100644 index 0000000000..8bcbdbd369 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -0,0 +1,392 @@ +/* + * + * 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.qpid.requestreply; + +import java.io.IOException; +import java.net.InetAddress; +import java.text.SimpleDateFormat; +import java.util.Date; + +import javax.jms.*; +import javax.naming.Context; + +import org.apache.log4j.Logger; + +/** + * PingPongBouncer is a message listener the bounces back messages to their reply to destination. This is used to return + * ping messages generated by {@link org.apache.qpid.requestreply.PingPongProducer} but could be used for other purposes + * too. + *

    + *

    The correlation id from the received message is extracted, and placed into the reply as the correlation id. Messages + * are bounced back to their reply-to destination. The original sender of the message has the option to use either a unique + * temporary queue or the correlation id to correlate the original message to the reply. + *

    + *

    There is a verbose mode flag which causes information about each ping to be output to the console + * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should + * be disabled for real timing tests as writing to the console will slow things down. + *

    + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Bounce back messages to their reply to destination. + *
    Provide command line invocation to start the bounce back on a configurable broker url. + *
    + * + * @todo Replace the command line parsing with a neater tool. + * @todo Make verbose accept a number of messages, only prints to console every X messages. + */ +public class PingPongBouncer implements MessageListener +{ + private static final Logger _logger = Logger.getLogger(PingPongBouncer.class); + + /** + * The default prefetch size for the message consumer. + */ + private static final int PREFETCH = 1; + + /** + * The default no local flag for the message consumer. + */ + private static final boolean NO_LOCAL = true; + + private static final String DEFAULT_DESTINATION_NAME = "ping"; + + /** + * The default exclusive flag for the message consumer. + */ + private static final boolean EXCLUSIVE = false; + + /** + * A convenient formatter to use when time stamping output. + */ + protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); + + /** + * Used to indicate that the reply generator should log timing info to the console (logger info level). + */ + private boolean _verbose = false; + + /** + * Determines whether this bounce back client bounces back messages persistently. + */ + private boolean _persistent = false; + + private Destination _consumerDestination; + + /** + * Keeps track of the response destination of the previous message for the last reply to producer cache. + */ + private Destination _lastResponseDest; + + /** + * The producer for sending replies with. + */ + private MessageProducer _replyProducer; + + /** + * The consumer controlSession. + */ + private Session _consumerSession; + + /** + * The producer controlSession. + */ + private Session _producerSession; + + /** + * Holds the connection to the broker. + */ + private Connection _connection; + + /** + * Flag used to indicate if this is a point to point or pub/sub ping client. + */ + private boolean _isPubSub = false; + + /** + * This flag is used to indicate that the user should be prompted to kill a broker, in order to test + * failover, immediately before committing a transaction. + */ + protected boolean _failBeforeCommit = false; + + /** + * This flag is used to indicate that the user should be prompted to a kill a broker, in order to test + * failover, immediate after committing a transaction. + */ + protected boolean _failAfterCommit = false; + + /** + * Creates a PingPongBouncer on the specified producer and consumer sessions. + * + * @param fileProperties The path to the file properties + * @param factoryName The factory name + * @param username The broker username. + * @param password The broker password. + * @param destinationName The name of the queue to receive pings on + * (or root of the queue name where many queues are generated). + * @param persistent A flag to indicate that persistent message should be used. + * @param transacted A flag to indicate that pings should be sent within transactions. + * @param selector A message selector to filter received pings with. + * @param verbose A flag to indicate that message timings should be sent to the console. + * @throws Exception All underlying exceptions allowed to fall through. This is only test code... + */ + public PingPongBouncer(String fileProperties, String factoryName, String username, String password, + String destinationName, boolean persistent, boolean transacted, + String selector, boolean verbose, boolean pubsub) throws Exception + { + // Create a client id to uniquely identify this client. + InetAddress address = InetAddress.getLocalHost(); + String clientId = address.getHostName() + System.currentTimeMillis(); + _verbose = verbose; + _persistent = persistent; + setPubSub(pubsub); + // Connect to the broker. + Context context = InitialContextHelper.getInitialContext(fileProperties); + ConnectionFactory factory = (ConnectionFactory) context.lookup(factoryName); + setConnection(factory.createConnection(username, password)); + + // Create a controlSession to listen for messages on and one to send replies on, transactional depending on the + // command line option. + _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + + // Create the queue to listen for message on. + createConsumerDestination(destinationName); + MessageConsumer consumer = _consumerSession.createConsumer(_consumerDestination, selector, NO_LOCAL); + + // Create a producer for the replies, without a default destination. + _replyProducer = _producerSession.createProducer(null); + _replyProducer.setDisableMessageTimestamp(true); + _replyProducer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + // Set this up to listen for messages on the queue. + consumer.setMessageListener(this); + } + + private static void usage() + { + System.err.println( + "Usage: PingPongBouncer \n" + "-host : broker host\n" + "-port : broker port\n" + "-destinationname : queue/topic name\n" + "-transacted : (true/false). Default is false\n" + "-persistent : (true/false). Default is false\n" + "-pubsub : (true/false). Default is false\n" + "-selector : selector string\n"); + } + + /** + * This is a callback method that is notified of all messages for which this has been registered as a message + * listener on a message consumer. It sends a reply (pong) to all messages it receieves on the reply to + * destination of the message. + * + * @param message The message that triggered this callback. + */ + public void onMessage(Message message) + { + try + { + String messageCorrelationId = message.getJMSCorrelationID(); + if (_verbose) + { + _logger.info(timestampFormatter + .format(new Date()) + ": Got ping with correlation id, " + messageCorrelationId); + } + + // Get the reply to destination from the message and check it is set. + Destination responseDest = message.getJMSReplyTo(); + + if (responseDest == null) + { + _logger.debug("Cannot send reply because reply-to destination is null."); + + return; + } + + // Spew out some timing information if verbose mode is on. + if (_verbose) + { + Long timestamp = message.getLongProperty("timestamp"); + + if (timestamp != null) + { + long diff = System.currentTimeMillis() - timestamp; + _logger.info("Time to bounce point: " + diff); + } + } + + // Correlate the reply to the original. + message.setJMSCorrelationID(messageCorrelationId); + + // Send the receieved message as the pong reply. + _replyProducer.send(responseDest, message); + + if (_verbose) + { + _logger.info(timestampFormatter + .format(new Date()) + ": Sent reply with correlation id, " + messageCorrelationId); + } + + // Commit the transaction if running in transactional mode. + commitTx(_producerSession); + } + catch (JMSException e) + { + _logger.debug("There was a JMSException: " + e.getMessage(), e); + } + } + + /** + * Gets the underlying connection that this ping client is running on. + * + * @return The underlying connection that this ping client is running on. + */ + public Connection getConnection() + { + return _connection; + } + + /** + * Sets the connection that this ping client is using. + * + * @param connection The ping connection. + */ + public void setConnection(Connection connection) + { + this._connection = connection; + } + + /** + * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic. + * + * @param pubsub true if this client is pinging a topic, false if it is pinging a queue. + */ + public void setPubSub(boolean pubsub) + { + _isPubSub = pubsub; + } + + /** + * Checks whether this client is a p2p or pub/sub ping client. + * + * @return true if this client is pinging a topic, false if it is pinging a queue. + */ + public boolean isPubSub() + { + return _isPubSub; + } + + /** + * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not + * a transactional controlSession, this method does nothing. + *

    + *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the + * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker + * after the commit is applied. + * + * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + */ + protected void commitTx(Session session) throws JMSException + { + if (session.getTransacted()) + { + try + { + if (_failBeforeCommit) + { + _logger.trace("Failing Before Commit"); + doFailover(); + } + + session.commit(); + + if (_failAfterCommit) + { + _logger.trace("Failing After Commit"); + doFailover(); + } + + _logger.trace("Session Commited."); + } + catch (JMSException e) + { + _logger.trace("JMSException on commit:" + e.getMessage(), e); + + try + { + session.rollback(); + _logger.debug("Message rolled back."); + } + catch (JMSException jmse) + { + _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); + + // Both commit and rollback failed. Throw the rollback exception. + throw jmse; + } + } + } + } + + /** + * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + * + * @param broker The name of the broker to terminate. + */ + protected void doFailover(String broker) + { + System.out.println("Kill Broker " + broker + " now."); + try + { + System.in.read(); + } + catch (IOException e) + { + } + + System.out.println("Continuing."); + } + + /** + * Prompts the user to terminate the broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + */ + protected void doFailover() + { + System.out.println("Kill Broker now."); + try + { + System.in.read(); + } + catch (IOException e) + { + } + + System.out.println("Continuing."); + + } + + private void createConsumerDestination(String name) throws JMSException + { + if (isPubSub()) + { + _consumerDestination = _consumerSession.createTopic(name); + } + else + { + _consumerDestination = _consumerSession.createQueue(name); + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java index a6b74911e1..780589768f 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java @@ -186,12 +186,12 @@ public class PingPongTestPerf extends AsymptoticTestCase synchronized (this) { // Establish a bounce back client on the ping queue to bounce back the pings. - /* perThreadSetup._testPingBouncer = + perThreadSetup._testPingBouncer = new PingPongBouncer(fileProperties, factoryName, username, password, destinationName, persistent, transacted, selector, verbose, pubsub); // Start the connections for client and producer running. - perThreadSetup._testPingBouncer.getConnection().start();*/ + perThreadSetup._testPingBouncer.getConnection().start(); // Establish a ping-pong client on the ping queue to send the pings and receive replies with. perThreadSetup._testPingProducer = new PingPongProducer(testParameters); @@ -246,6 +246,6 @@ public class PingPongTestPerf extends AsymptoticTestCase /** * Holds the test ping client. */ - //private PingPongBouncer _testPingBouncer; + private PingPongBouncer _testPingBouncer; } } -- cgit v1.2.1 From 0a45328fc13a926f62911d8cea4a9936e754293d Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Mon, 29 Oct 2007 14:46:28 +0000 Subject: Changed to set session and initial context git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@589643 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/requestreply/InitialContextHelper.java | 7 +++++++ .../main/java/org/apache/qpid/requestreply/PingPongProducer.java | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/InitialContextHelper.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/InitialContextHelper.java index 067aad4095..b684fd6b9b 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/InitialContextHelper.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/InitialContextHelper.java @@ -42,7 +42,14 @@ public class InitialContextHelper ClassLoader cl = Thread.currentThread().getContextClassLoader(); // NB: Need to change path to reflect package if moving classes around ! InputStream is = cl.getResourceAsStream(propertyFile); + if( is != null ) + { fileProperties.load(is); return new InitialContext(fileProperties); + } + else + { + return new InitialContext(); + } } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 638f5ae8c0..6860b57d26 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -558,7 +558,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti /** * Holds the producer controlSession, needed to create ping messages. */ - protected Session _producerSession = (Session) _connection.createSession(_transacted, _ackMode); + protected Session _producerSession ; /** * Holds the destination where the response messages will arrive. -- cgit v1.2.1 From 18ead2882fa24b42e5f2e170a284f91f3eaacf07 Mon Sep 17 00:00:00 2001 From: Rupert Smith Date: Fri, 9 Nov 2007 15:31:03 +0000 Subject: Merged perf test latest from M2.1 onto trunk. Many fixes and now tests through pure JMS. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@593566 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/ping/PingClient.java | 4 +- .../org/apache/qpid/ping/PingLatencyTestPerf.java | 8 +- .../apache/qpid/requestreply/PingPongProducer.java | 1158 ++++++++++---------- 3 files changed, 603 insertions(+), 567 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java index ac12436951..b9632eee4c 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java @@ -93,13 +93,13 @@ public class PingClient extends PingPongProducer if (_isUnique) { - log.debug("1 consumer per destination."); + log.debug(_noOfConsumers + " consumer per destination."); return _noOfConsumers; } else { - log.debug(_pingClientCount + " consumers per destination."); + log.debug((_pingClientCount * _noOfConsumers) + " consumers per destination."); return _pingClientCount * _noOfConsumers; } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java index f05d13e4e2..55414664da 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java @@ -25,6 +25,9 @@ import junit.framework.TestSuite; import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.message.AMQMessage; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.requestreply.PingPongProducer; import uk.co.thebadgerset.junit.extensions.TimingController; @@ -33,6 +36,7 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; import javax.jms.JMSException; import javax.jms.Message; +import javax.jms.ObjectMessage; import java.util.Collections; import java.util.HashMap; @@ -242,7 +246,9 @@ public class PingLatencyTestPerf extends PingTestPerf implements TimingControlle public BatchedResultsListener(int batchSize) { _batchSize = batchSize; - _strictAMQP = false; + _strictAMQP = + Boolean.parseBoolean(System.getProperties().getProperty(AMQSession.STRICT_AMQP, + AMQSession.STRICT_AMQP_DEFAULT)); } /** diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 6860b57d26..c3689151d2 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -21,23 +21,27 @@ package org.apache.qpid.requestreply; import org.apache.log4j.Logger; +import org.apache.log4j.NDC; -import org.apache.qpid.client.message.TestMessageFactory; -import org.apache.qpid.util.CommandLineParser; +import org.apache.qpid.test.framework.TestUtils; import uk.co.thebadgerset.junit.extensions.BatchedThrottle; import uk.co.thebadgerset.junit.extensions.Throttle; +import uk.co.thebadgerset.junit.extensions.util.CommandLineParser; import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; import javax.jms.*; import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; -import java.io.IOException; +import java.io.*; import java.net.InetAddress; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -48,16 +52,16 @@ import java.util.concurrent.atomic.AtomicLong; * to its own messages and does not send replies (see {@link org.apache.qpid.ping.PingClient}). The intention of ping * pong producer is that it is a swiss-army knife test client that makes almost every aspect of its behaviour * configurable. - *

    + * *

    The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. This * means that this class has to do some work to correlate pings with pongs; it expectes the original message correlation * id in the ping to be bounced back in the reply correlation id. - *

    + * *

    This ping tool accepts a vast number of configuration options, all of which are passed in to the constructor. It * can ping topics or queues; ping multiple destinations; do persistent pings; send messages of any size; do pings within * transactions; control the number of pings to send in each transaction; limit its sending rate; and perform failover * testing. A complete list of accepted parameters, default values and comments on their usage is provided here: - *

    + * *

    *
    Parameters
    Parameter Default Comments *
    messageSize 0 Message size in bytes. Not including any headers. @@ -84,317 +88,256 @@ import java.util.concurrent.atomic.AtomicLong; *
    uniqueDests true Whether each receivers only listens to one ping destination or all. *
    durableDests false Whether or not durable destinations are used. *
    ackMode AUTO_ACK The message acknowledgement mode. Possible values are: - * 0 - SESSION_TRANSACTED - * 1 - AUTO_ACKNOWLEDGE - * 2 - CLIENT_ACKNOWLEDGE - * 3 - DUPS_OK_ACKNOWLEDGE - * 257 - NO_ACKNOWLEDGE - * 258 - PRE_ACKNOWLEDGE + * 0 - SESSION_TRANSACTED + * 1 - AUTO_ACKNOWLEDGE + * 2 - CLIENT_ACKNOWLEDGE + * 3 - DUPS_OK_ACKNOWLEDGE + * 257 - NO_ACKNOWLEDGE + * 258 - PRE_ACKNOWLEDGE *
    consTransacted false Whether or not consumers use transactions. Defaults to the same value - * as the 'transacted' option if not seperately defined. + * as the 'transacted' option if not seperately defined. *
    consAckMode AUTO_ACK The message acknowledgement mode for consumers. Defaults to the same - * value as 'ackMode' if not seperately defined. + * value as 'ackMode' if not seperately defined. *
    maxPending 0 The maximum size in bytes, of messages sent but not yet received. - * Limits the volume of messages currently buffered on the client - * or broker. Can help scale test clients by limiting amount of buffered - * data to avoid out of memory errors. + * Limits the volume of messages currently buffered on the client + * or broker. Can help scale test clients by limiting amount of buffered + * data to avoid out of memory errors. *
    - *

    + * *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so by * starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is also * registered to terminate the ping-pong loop cleanly. - *

    + * *

    *
    CRC Card
    Responsibilities Collaborations *
    Provide a ping and wait for all responses cycle. *
    Provide command line invocation to loop the ping cycle on a configurable broker url. *
    * - * @todo Make the message listener a static for all replies to be sent to? It won't be any more of a bottle neck than having - * one per PingPongProducer, as will synchronize on message correlation id, allowing threads to process messages - * concurrently for different ids. Needs to be static so that when using a chained message listener and shared - * destinations between multiple PPPs, it gets notified about all replies, not just those that happen to be picked up - * by the PPP that it is atteched to. * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock pair. - * Obtain read lock on all messages, before decrementing the message count. At the end of the on message method add a - * block that obtains the write lock for the very last message, releases any waiting producer. Means that the last - * message waits until all other messages have been handled before releasing producers but allows messages to be - * processed concurrently, unlike the current synchronized block. - * @todo Get rid of pauses between batches, it will impact the timing statistics, and generate meanigless timings. - * Instead make mina use a bounded blocking buffer, or other form of back pressure, to stop data being written - * faster than it can be sent. + * Obtain read lock on all messages, before decrementing the message count. At the end of the on message method add a + * block that obtains the write lock for the very last message, releases any waiting producer. Means that the last + * message waits until all other messages have been handled before releasing producers but allows messages to be + * processed concurrently, unlike the current synchronized block. */ -public class PingPongProducer implements Runnable /*, MessageListener*/, ExceptionListener +public class PingPongProducer implements Runnable, ExceptionListener { - /** - * Used for debugging. - */ - private static final Logger _log = Logger.getLogger(PingPongProducer.class); + /** Used for debugging. */ + private static final Logger log = Logger.getLogger(PingPongProducer.class); - /** - * Helds the factory name - */ + /** Holds the name of the property to determine whether of not client id is overridden at connection time. */ + public static final String OVERRIDE_CLIENT_ID_PROPNAME = "overrideClientId"; + + /** Holds the default value of the override client id flag. */ + public static final String OVERRIDE_CLIENT_ID_DEAFULT = "false"; + + /** Holds the name of the property to define the JNDI factory name with. */ public static final String FACTORY_NAME_PROPNAME = "factoryName"; + + /** Holds the default JNDI name of the connection factory. */ public static final String FACTORY_NAME_DEAFULT = "local"; - /** - * Helds the file properties name - */ + /** Holds the name of the property to set the JNDI initial context properties with. */ public static final String FILE_PROPERTIES_PROPNAME = "properties"; - public static final String FILE_PROPERTIES_DEAFULT = "/perftests.properties"; - /** - * Holds the name of the property to get the test message size from. - */ + /** Holds the default file name of the JNDI initial context properties. */ + public static final String FILE_PROPERTIES_DEAFULT = "perftests.properties"; + + /** Holds the name of the property to get the test message size from. */ public static final String MESSAGE_SIZE_PROPNAME = "messageSize"; - /** - * Used to set up a default message size. - */ + /** Used to set up a default message size. */ public static final int MESSAGE_SIZE_DEAFULT = 0; - /** - * Holds the name of the property to get the ping queue name from. - */ + /** Holds the name of the property to get the ping queue name from. */ public static final String PING_QUEUE_NAME_PROPNAME = "destinationName"; - /** - * Holds the name of the default destination to send pings on. - */ + /** Holds the name of the default destination to send pings on. */ public static final String PING_QUEUE_NAME_DEFAULT = "ping"; - /** - * Holds the name of the property to get the test delivery mode from. - */ + /** Holds the name of the property to get the queue name postfix from. */ + public static final String QUEUE_NAME_POSTFIX_PROPNAME = "queueNamePostfix"; + + /** Holds the default queue name postfix value. */ + public static final String QUEUE_NAME_POSTFIX_DEFAULT = ""; + + /** Holds the name of the property to get the test delivery mode from. */ public static final String PERSISTENT_MODE_PROPNAME = "persistent"; - /** - * Holds the message delivery mode to use for the test. - */ + /** Holds the message delivery mode to use for the test. */ public static final boolean PERSISTENT_MODE_DEFAULT = false; - /** - * Holds the name of the property to get the test transactional mode from. - */ + /** Holds the name of the property to get the test transactional mode from. */ public static final String TRANSACTED_PROPNAME = "transacted"; - /** - * Holds the transactional mode to use for the test. - */ + /** Holds the transactional mode to use for the test. */ public static final boolean TRANSACTED_DEFAULT = false; + /** Holds the name of the property to get the test consumer transacted mode from. */ public static final String CONSUMER_TRANSACTED_PROPNAME = "consTransacted"; + + /** Holds the consumer transactional mode default setting. */ public static final boolean CONSUMER_TRANSACTED_DEFAULT = false; - /** - * Holds the name of the property to get the message rate from. - */ + /** Holds the name of the property to get the test broker url from. */ + public static final String BROKER_PROPNAME = "broker"; + + /** Holds the default broker url for the test. */ + public static final String BROKER_DEFAULT = "tcp://localhost:5672"; + + /** Holds the name of the property to get the test broker virtual path. */ + public static final String VIRTUAL_HOST_PROPNAME = "virtualHost"; + + /** Holds the default virtual path for the test. */ + public static final String VIRTUAL_HOST_DEFAULT = ""; + + /** Holds the name of the property to get the message rate from. */ public static final String RATE_PROPNAME = "rate"; - /** - * Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. - */ + /** Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. */ public static final int RATE_DEFAULT = 0; - /** - * Holds the name of the property to get the verbose mode proeprty from. - */ + /** Holds the name of the property to get the verbose mode proeprty from. */ public static final String VERBOSE_PROPNAME = "verbose"; - /** - * Holds the default verbose mode. - */ + /** Holds the default verbose mode. */ public static final boolean VERBOSE_DEFAULT = false; - /** - * Holds the name of the property to get the p2p or pub/sub messaging mode from. - */ + /** Holds the name of the property to get the p2p or pub/sub messaging mode from. */ public static final String PUBSUB_PROPNAME = "pubsub"; - /** - * Holds the pub/sub mode default, true means ping a topic, false means ping a queue. - */ + /** Holds the pub/sub mode default, true means ping a topic, false means ping a queue. */ public static final boolean PUBSUB_DEFAULT = false; - /** - * Holds the name of the property to get the fail after commit flag from. - */ + /** Holds the name of the property to get the fail after commit flag from. */ public static final String FAIL_AFTER_COMMIT_PROPNAME = "failAfterCommit"; - /** - * Holds the default failover after commit test flag. - */ + /** Holds the default failover after commit test flag. */ public static final boolean FAIL_AFTER_COMMIT_DEFAULT = false; - /** - * Holds the name of the proeprty to get the fail before commit flag from. - */ + /** Holds the name of the proeprty to get the fail before commit flag from. */ public static final String FAIL_BEFORE_COMMIT_PROPNAME = "failBeforeCommit"; - /** - * Holds the default failover before commit test flag. - */ + /** Holds the default failover before commit test flag. */ public static final boolean FAIL_BEFORE_COMMIT_DEFAULT = false; - /** - * Holds the name of the proeprty to get the fail after send flag from. - */ + /** Holds the name of the proeprty to get the fail after send flag from. */ public static final String FAIL_AFTER_SEND_PROPNAME = "failAfterSend"; - /** - * Holds the default failover after send test flag. - */ + /** Holds the default failover after send test flag. */ public static final boolean FAIL_AFTER_SEND_DEFAULT = false; - /** - * Holds the name of the property to get the fail before send flag from. - */ + /** Holds the name of the property to get the fail before send flag from. */ public static final String FAIL_BEFORE_SEND_PROPNAME = "failBeforeSend"; - /** - * Holds the default failover before send test flag. - */ + /** Holds the default failover before send test flag. */ public static final boolean FAIL_BEFORE_SEND_DEFAULT = false; - /** - * Holds the name of the property to get the fail once flag from. - */ + /** Holds the name of the property to get the fail once flag from. */ public static final String FAIL_ONCE_PROPNAME = "failOnce"; - /** - * The default failover once flag, true means only do one failover, false means failover on every commit cycle. - */ + /** The default failover once flag, true means only do one failover, false means failover on every commit cycle. */ public static final boolean FAIL_ONCE_DEFAULT = true; - /** - * Holds the name of the property to get the broker access username from. - */ + /** Holds the name of the property to get the broker access username from. */ public static final String USERNAME_PROPNAME = "username"; - /** - * Holds the default broker _log on username. - */ + /** Holds the default broker log on username. */ public static final String USERNAME_DEFAULT = "guest"; - /** - * Holds the name of the property to get the broker access password from. - */ + /** Holds the name of the property to get the broker access password from. */ public static final String PASSWORD_PROPNAME = "password"; - /** - * Holds the default broker _log on password. - */ + /** Holds the default broker log on password. */ public static final String PASSWORD_DEFAULT = "guest"; - /** - * Holds the name of the proeprty to get the. - */ + /** Holds the name of the proeprty to get the. */ public static final String SELECTOR_PROPNAME = "selector"; - /** - * Holds the default message selector. - */ + /** Holds the default message selector. */ public static final String SELECTOR_DEFAULT = ""; - /** - * Holds the name of the property to get the destination count from. - */ + /** Holds the name of the property to get the destination count from. */ public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; - /** - * Defines the default number of destinations to ping. - */ + /** Defines the default number of destinations to ping. */ public static final int DESTINATION_COUNT_DEFAULT = 1; - /** - * Holds the name of the property to get the number of consumers per destination from. - */ + /** Holds the name of the property to get the number of consumers per destination from. */ public static final String NUM_CONSUMERS_PROPNAME = "numConsumers"; - /** - * Defines the default number consumers per destination. - */ + /** Defines the default number consumers per destination. */ public static final int NUM_CONSUMERS_DEFAULT = 1; - /** - * Holds the name of the property to get the waiting timeout for response messages. - */ + /** Holds the name of the property to get the waiting timeout for response messages. */ public static final String TIMEOUT_PROPNAME = "timeout"; - /** - * Default time to wait before assuming that a ping has timed out. - */ + /** Default time to wait before assuming that a ping has timed out. */ public static final long TIMEOUT_DEFAULT = 30000; - /** - * Holds the name of the property to get the commit batch size from. - */ + /** Holds the name of the property to get the commit batch size from. */ public static final String TX_BATCH_SIZE_PROPNAME = "commitBatchSize"; - /** - * Defines the default number of pings to send in each transaction when running transactionally. - */ + /** Defines the default number of pings to send in each transaction when running transactionally. */ public static final int TX_BATCH_SIZE_DEFAULT = 1; - /** - * Holds the name of the property to get the unique destinations flag from. - */ + /** Holds the name of the property to get the unique destinations flag from. */ public static final String UNIQUE_DESTS_PROPNAME = "uniqueDests"; - /** - * Defines the default value for the unique destinations property. - */ + /** Defines the default value for the unique destinations property. */ public static final boolean UNIQUE_DESTS_DEFAULT = true; - /** - * Holds the name of the proeprty to get the message acknowledgement mode from. - */ + /** Holds the name of the property to get the durable destinations flag from. */ + public static final String DURABLE_DESTS_PROPNAME = "durableDests"; + + /** Defines the default value of the durable destinations flag. */ + public static final boolean DURABLE_DESTS_DEFAULT = false; + + /** Holds the name of the proeprty to get the message acknowledgement mode from. */ public static final String ACK_MODE_PROPNAME = "ackMode"; - /** - * Defines the default message acknowledgement mode. - */ + /** Defines the default message acknowledgement mode. */ public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; + /** Holds the name of the property to get the consumers message acknowledgement mode from. */ public static final String CONSUMER_ACK_MODE_PROPNAME = "consAckMode"; + + /** Defines the default consumers message acknowledgement mode. */ public static final int CONSUMER_ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; + /** Holds the name of the property to get the maximum pending message size setting from. */ public static final String MAX_PENDING_PROPNAME = "maxPending"; + + /** Defines the default value for the maximum pending message size setting. 0 means no limit. */ public static final int MAX_PENDING_DEFAULT = 0; - /** - * Defines the default prefetch size to use when consuming messages. - */ + /** Defines the default prefetch size to use when consuming messages. */ public static final int PREFETCH_DEFAULT = 100; - /** - * Defines the default value of the no local flag to use when consuming messages. - */ + /** Defines the default value of the no local flag to use when consuming messages. */ public static final boolean NO_LOCAL_DEFAULT = false; - /** - * Defines the default value of the exclusive flag to use when consuming messages. - */ + /** Defines the default value of the exclusive flag to use when consuming messages. */ public static final boolean EXCLUSIVE_DEFAULT = false; - /** - * Holds the name of the property to store nanosecond timestamps in ping messages with. - */ + /** Holds the name of the property to store nanosecond timestamps in ping messages with. */ public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp"; - /** - * Holds the default configuration properties. - */ + /** Holds the default configuration properties. */ public static ParsedProperties defaults = new ParsedProperties(); static { + defaults.setPropertyIfNull(OVERRIDE_CLIENT_ID_PROPNAME, OVERRIDE_CLIENT_ID_DEAFULT); defaults.setPropertyIfNull(FILE_PROPERTIES_PROPNAME, FILE_PROPERTIES_DEAFULT); defaults.setPropertyIfNull(FACTORY_NAME_PROPNAME, FACTORY_NAME_DEAFULT); + defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT); defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT); defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT); + defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT); defaults.setPropertyIfNull(PING_QUEUE_NAME_PROPNAME, PING_QUEUE_NAME_DEFAULT); + defaults.setPropertyIfNull(QUEUE_NAME_POSTFIX_PROPNAME, QUEUE_NAME_POSTFIX_DEFAULT); defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT); defaults.setPropertyIfNull(TRANSACTED_PROPNAME, TRANSACTED_DEFAULT); defaults.setPropertyIfNull(CONSUMER_TRANSACTED_PROPNAME, CONSUMER_TRANSACTED_DEFAULT); @@ -405,6 +348,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT); defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT); defaults.setPropertyIfNull(UNIQUE_DESTS_PROPNAME, UNIQUE_DESTS_DEFAULT); + defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT); defaults.setPropertyIfNull(FAIL_BEFORE_COMMIT_PROPNAME, FAIL_BEFORE_COMMIT_DEFAULT); defaults.setPropertyIfNull(FAIL_AFTER_COMMIT_PROPNAME, FAIL_AFTER_COMMIT_DEFAULT); defaults.setPropertyIfNull(FAIL_BEFORE_SEND_PROPNAME, FAIL_BEFORE_SEND_DEFAULT); @@ -418,92 +362,91 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT); } + /** Allows setting of client ID on the connection, rather than through the connection URL. */ + protected boolean _overrideClientId; + + /** Holds the JNDI name of the JMS connection factory. */ protected String _factoryName; + + /** Holds the name of the properties file to configure JNDI with. */ protected String _fileProperties; + + /** Holds the broker url. */ protected String _brokerDetails; + + /** Holds the username to access the broker with. */ protected String _username; + + /** Holds the password to access the broker with. */ protected String _password; + + /** Holds the virtual host on the broker to run the tests through. */ protected String _virtualpath; + + /** Holds the root name from which to generate test destination names. */ protected String _destinationName; + + /** Holds the default queue name postfix value. */ + protected String _queueNamePostfix; + + /** Holds the message selector to filter the pings with. */ protected String _selector; + + /** Holds the producers transactional mode flag. */ protected boolean _transacted; + + /** Holds the consumers transactional mode flag. */ protected boolean _consTransacted; - /** - * Determines whether this producer sends persistent messages. - */ + /** Determines whether this producer sends persistent messages. */ protected boolean _persistent; - /** - * Holds the acknowledgement mode used for sending and receiving messages. - */ + /** Holds the acknowledgement mode used for the producers. */ protected int _ackMode; + /** Holds the acknowledgement mode setting for the consumers. */ protected int _consAckMode; - /** - * Determines what size of messages this producer sends. - */ + /** Determines what size of messages this producer sends. */ protected int _messageSize; - /** - * Used to indicate that the ping loop should print out whenever it pings. - */ + /** Used to indicate that the ping loop should print out whenever it pings. */ protected boolean _verbose; - /** - * Flag used to indicate if this is a point to point or pub/sub ping client. - */ + /** Flag used to indicate if this is a point to point or pub/sub ping client. */ protected boolean _isPubSub; - /** - * Flag used to indicate if the destinations should be unique client. - */ + /** Flag used to indicate if the destinations should be unique client. */ protected boolean _isUnique; - /** - * Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. - */ + /** Flag used to indicate that durable destination should be used. */ + protected boolean _isDurable; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ protected boolean _failBeforeCommit; - /** - * Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. - */ + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ protected boolean _failAfterCommit; - /** - * Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. - */ + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ protected boolean _failBeforeSend; - /** - * Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. - */ + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ protected boolean _failAfterSend; - /** - * Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. - */ + /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ protected boolean _failOnce; - /** - * Holds the number of sends that should be performed in every transaction when using transactions. - */ + /** Holds the number of sends that should be performed in every transaction when using transactions. */ protected int _txBatchSize; - /** - * Holds the number of destinations to ping. - */ + /** Holds the number of destinations to ping. */ protected int _noOfDestinations; - /** - * Holds the number of consumers per destination. - */ + /** Holds the number of consumers per destination. */ protected int _noOfConsumers; - /** - * Holds the maximum send rate in herz. - */ + /** Holds the maximum send rate in herz. */ protected int _rate; /** @@ -512,72 +455,47 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ protected int _maxPendingSize; - /** - * Holds a monitor which is used to synchronize sender and receivers threads, where the sender has elected - * to wait until the number of unreceived message is reduced before continuing to send. - */ - protected Object _sendPauseMonitor = new Object(); + /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ + private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); - /** - * Keeps a count of the number of message currently sent but not received. - */ - protected AtomicInteger _unreceived = new AtomicInteger(0); + /** A source for providing sequential unqiue ids for instances of this class to be identifed with. */ + private static AtomicInteger _instanceIdGenerator = new AtomicInteger(0); - /** - * A source for providing sequential unique correlation ids. These will be unique within the same JVM. - */ - private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); + /** Holds this instances unique id. */ + private int instanceId; /** * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross multiple * ping producers on the same JVM. */ private static Map perCorrelationIds = - Collections.synchronizedMap(new HashMap()); + Collections.synchronizedMap(new HashMap()); - /** - * A convenient formatter to use when time stamping output. - */ + /** A convenient formatter to use when time stamping output. */ protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); - /** - * Holds the connection to the broker. - */ + /** Holds the connection for the message producer. */ protected Connection _connection; - /** - * Holds the consumer connections. - */ + /** Holds the consumer connections. */ protected Connection[] _consumerConnection; - /** - * Holds the controlSession on which ping replies are received. - */ + /** Holds the controlSession on which ping replies are received. */ protected Session[] _consumerSession; - /** - * Holds the producer controlSession, needed to create ping messages. - */ - protected Session _producerSession ; + /** Holds the producer controlSession, needed to create ping messages. */ + protected Session _producerSession; - /** - * Holds the destination where the response messages will arrive. - */ + /** Holds the destination where the response messages will arrive. */ protected Destination _replyDestination; - /** - * Holds the set of destinations that this ping producer pings. - */ + /** Holds the set of destinations that this ping producer pings. */ protected List _pingDestinations; - /** - * Used to restrict the sending rate to a specified limit. - */ + /** Used to restrict the sending rate to a specified limit. */ protected Throttle _rateLimiter; - /** - * Holds a message listener that this message listener chains all its messages to. - */ + /** Holds a message listener that this message listener chains all its messages to. */ protected ChainedMessageListener _chainedMessageListener = null; /** @@ -592,30 +510,34 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ protected AtomicInteger _queueSharedID = new AtomicInteger(); - /** - * Used to tell the ping loop when to terminate, it only runs while this is true. - */ + /** Used to tell the ping loop when to terminate, it only runs while this is true. */ protected boolean _publish = true; - /** - * Holds the message producer to send the pings through. - */ + /** Holds the message producer to send the pings through. */ protected MessageProducer _producer; - /** - * Holds the message consumer to receive the ping replies through. - */ + /** Holds the message consumer to receive the ping replies through. */ protected MessageConsumer[] _consumer; - /** - * The prompt to display when asking the user to kill the broker for failover testing. - */ + /** The prompt to display when asking the user to kill the broker for failover testing. */ private static final String KILL_BROKER_PROMPT = "Kill broker now, then press Return."; + /** Holds the name for this test client to be identified to the broker with. */ + private String _clientID; + + /** Keeps count of the total messages sent purely for debugging purposes. */ + private static AtomicInteger numSent = new AtomicInteger(); + /** - * Keeps count of the total messages sent purely for debugging purposes. + * Holds a monitor which is used to synchronize sender and receivers threads, where the sender has elected + * to wait until the number of unreceived message is reduced before continuing to send. This monitor is a + * fair SynchronousQueue becuase that provides fair scheduling, to ensure that all producer threads get an + * equal chance to produce messages. */ - private static AtomicInteger numSent = new AtomicInteger(); + static final SynchronousQueue _sendPauseMonitor = new SynchronousQueue(true); + + /** Keeps a count of the number of message currently sent but not received. */ + static AtomicInteger _unreceived = new AtomicInteger(0); /** * Creates a ping producer with the specified parameters, of which there are many. See the class level comments @@ -623,20 +545,28 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * it, to send and recieve its pings and replies on. * * @param overrides Properties containing any desired overrides to the defaults. + * * @throws Exception Any exceptions are allowed to fall through. */ public PingPongProducer(Properties overrides) throws Exception { - // _log.debug("public PingPongProducer(Properties overrides = " + overrides + "): called"); + // log.debug("public PingPongProducer(Properties overrides = " + overrides + "): called"); + instanceId = _instanceIdGenerator.getAndIncrement(); + // Create a set of parsed properties from the defaults overriden by the passed in values. ParsedProperties properties = new ParsedProperties(defaults); properties.putAll(overrides); + // Extract the configuration properties to set the pinger up with. + _overrideClientId = properties.getPropertyAsBoolean(OVERRIDE_CLIENT_ID_PROPNAME); _factoryName = properties.getProperty(FACTORY_NAME_PROPNAME); _fileProperties = properties.getProperty(FILE_PROPERTIES_PROPNAME); + _brokerDetails = properties.getProperty(BROKER_PROPNAME); _username = properties.getProperty(USERNAME_PROPNAME); _password = properties.getProperty(PASSWORD_PROPNAME); + _virtualpath = properties.getProperty(VIRTUAL_HOST_PROPNAME); _destinationName = properties.getProperty(PING_QUEUE_NAME_PROPNAME); + _queueNamePostfix = properties.getProperty(QUEUE_NAME_POSTFIX_PROPNAME); _selector = properties.getProperty(SELECTOR_PROPNAME); _transacted = properties.getPropertyAsBoolean(TRANSACTED_PROPNAME); _consTransacted = properties.getPropertyAsBoolean(CONSUMER_TRANSACTED_PROPNAME); @@ -654,20 +584,26 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti _rate = properties.getPropertyAsInteger(RATE_PROPNAME); _isPubSub = properties.getPropertyAsBoolean(PUBSUB_PROPNAME); _isUnique = properties.getPropertyAsBoolean(UNIQUE_DESTS_PROPNAME); - _ackMode = properties.getPropertyAsInteger(ACK_MODE_PROPNAME); - _consAckMode = properties.getPropertyAsInteger(CONSUMER_ACK_MODE_PROPNAME); + _isDurable = properties.getPropertyAsBoolean(DURABLE_DESTS_PROPNAME); + _ackMode = _transacted ? 0 : properties.getPropertyAsInteger(ACK_MODE_PROPNAME); + _consAckMode = _consTransacted ? 0 : properties.getPropertyAsInteger(CONSUMER_ACK_MODE_PROPNAME); _maxPendingSize = properties.getPropertyAsInteger(MAX_PENDING_PROPNAME); + // Check that one or more destinations were specified. if (_noOfDestinations < 1) { throw new IllegalArgumentException("There must be at least one destination."); } + // Set up a throttle to control the send rate, if a rate > 0 is specified. if (_rate > 0) { _rateLimiter = new BatchedThrottle(); _rateLimiter.setRate(_rate); } + + // Create the connection and message producers/consumers. + // establishConnection(true, true); } /** @@ -676,15 +612,17 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * * @param producer Flag to indicate whether or not the producer should be set up. * @param consumer Flag to indicate whether or not the consumers should be set up. + * * @throws Exception Any exceptions are allowed to fall through. */ public void establishConnection(boolean producer, boolean consumer) throws Exception { - // _log.debug("public void establishConnection(): called"); + // log.debug("public void establishConnection(): called"); // Generate a unique identifying name for this client, based on it ip address and the current time. InetAddress address = InetAddress.getLocalHost(); - String _clientID = address.getHostName() + System.currentTimeMillis(); + // _clientID = address.getHostName() + System.currentTimeMillis(); + _clientID = "perftest_" + instanceId; // Create a connection to the broker. createConnection(_clientID); @@ -701,7 +639,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti // Create the destinations to send pings to and receive replies from. _replyDestination = _consumerSession[0].createTemporaryQueue(); - createPingDestinations(_noOfDestinations, _selector, _destinationName); + createPingDestinations(_noOfDestinations, _selector, _destinationName, _isUnique, _isDurable); // Create the message producer only if instructed to. if (producer) @@ -721,17 +659,30 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * created with. * * @param clientID The clients identifier. - * @throws Exception Any underlying exceptions are allowed to fall through. + * + * @throws JMSException Underlying exceptions allowed to fall through. + * @throws NamingException Underlying exceptions allowed to fall through. + * @throws IOException Underlying exceptions allowed to fall through. */ - protected void createConnection(String clientID) throws Exception + protected void createConnection(String clientID) throws JMSException, NamingException, IOException { // _log.debug("protected void createConnection(String clientID = " + clientID + "): called"); // _log.debug("Creating a connection for the message producer."); - Context context = InitialContextHelper.getInitialContext(_fileProperties); + File propsFile = new File(_fileProperties); + InputStream is = new FileInputStream(propsFile); + Properties properties = new Properties(); + properties.load(is); + + Context context = new InitialContext(properties); ConnectionFactory factory = (ConnectionFactory) context.lookup(_factoryName); _connection = factory.createConnection(_username, _password); + if (_overrideClientId) + { + _connection.setClientID(clientID); + } + // _log.debug("Creating " + _noOfConsumers + " connections for the consumers."); _consumerConnection = new Connection[_noOfConsumers]; @@ -739,6 +690,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti for (int i = 0; i < _noOfConsumers; i++) { _consumerConnection[i] = factory.createConnection(_username, _password); + // _consumerConnection[i].setClientID(clientID); } } @@ -752,8 +704,8 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti { try { - Properties options = CommandLineParser - .processCommandLine(args, new CommandLineParser(new String[][]{}), System.getProperties()); + Properties options = + CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); // Create a ping producer overriding its defaults with all options passed on the command line. PingPongProducer pingProducer = new PingPongProducer(options); @@ -776,7 +728,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti catch (Exception e) { System.err.println(e.getMessage()); - _log.error("Top level handler caught execption.", e); + log.error("Top level handler caught execption.", e); System.exit(1); } } @@ -795,9 +747,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti Thread.sleep(sleepTime); } catch (InterruptedException ie) - { - // do nothing - } + { } } } @@ -809,12 +759,12 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ public List getReplyDestinations() { - // _log.debug("public List getReplyDestinations(): called"); + // log.debug("public List getReplyDestinations(): called"); List replyDestinations = new ArrayList(); replyDestinations.add(_replyDestination); - // _log.debug("replyDestinations = " + replyDestinations); + // log.debug("replyDestinations = " + replyDestinations); return replyDestinations; } @@ -827,12 +777,12 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ public void createProducer() throws JMSException { - _producer = _producerSession.createProducer(null); + // log.debug("public void createProducer(): called"); + + _producer = (MessageProducer) _producerSession.createProducer(null); _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - if (_log.isDebugEnabled()) - { - _log.debug("Created producer for " + (_persistent ? "persistent" : "non-persistent") + " messages."); - } + + // log.debug("Created producer for " + (_persistent ? "persistent" : "non-persistent") + " messages."); } /** @@ -842,43 +792,57 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * @param noOfDestinations The number of destinations to create consumers for. * @param selector The message selector to filter the consumers with. * @param rootName The root of the name, or actual name if only one is being created. + * @param unique true to make the destinations unique to this pinger, false to share the + * numbering with all pingers on the same JVM. + * @param durable If the destinations are durable topics. + * * @throws JMSException Any JMSExceptions are allowed to fall through. */ - public void createPingDestinations(int noOfDestinations, String selector, String rootName) throws JMSException + public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique, + boolean durable) throws JMSException { - if (_log.isDebugEnabled()) - { - _log.debug( - "public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " + selector + ", String rootName = " + rootName); - } + /*log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " + + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = " + + durable + "): called");*/ + _pingDestinations = new ArrayList(); + // Create the desired number of ping destinations and consumers for them. - if (_log.isDebugEnabled()) - { - _log.debug("Creating " + noOfDestinations + " destinations to ping."); - } - String id; + // log.debug("Creating " + noOfDestinations + " destinations to ping."); + for (int i = 0; i < noOfDestinations; i++) { Destination destination; - id = "_" + _queueSharedID.incrementAndGet(); + String id; + + // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag. + if (unique) + { + // log.debug("Creating unique destinations."); + id = "_" + _queueJVMSequenceID.incrementAndGet() + "_" + _connection.getClientID(); + } + else + { + // log.debug("Creating shared destinations."); + id = "_" + _queueSharedID.incrementAndGet(); + } + // Check if this is a pub/sub pinger, in which case create topics. if (_isPubSub) { destination = _producerSession.createTopic(rootName + id); - if (_log.isDebugEnabled()) + // log.debug("Created non-durable topic " + destination); + + if (durable) { - _log.debug("Created topic " + rootName + id); + _producerSession.createDurableSubscriber((Topic) destination, _connection.getClientID()); } } // Otherwise this is a p2p pinger, in which case create queues. else { - destination = _producerSession.createQueue(rootName + id); - if (_log.isDebugEnabled()) - { - _log.debug("Created queue " + rootName + id); - } + destination = _producerSession.createQueue(rootName + id + _queueNamePostfix); + // log.debug("Created queue " + destination); } // Keep the destination. @@ -891,16 +855,17 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * * @param destinations The destinations to listen to. * @param selector A selector to filter the messages with. + * * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through. */ public void createReplyConsumers(Collection destinations, String selector) throws JMSException { - /*_log.debug("public void createReplyConsumers(Collection destinations = " + destinations + /*log.debug("public void createReplyConsumers(Collection destinations = " + destinations + ", String selector = " + selector + "): called");*/ - // _log.debug("There are " + destinations.size() + " destinations."); - // _log.debug("Creating " + _noOfConsumers + " consumers on each destination."); - // _log.debug("Total number of consumers is: " + (destinations.size() * _noOfConsumers)); + log.debug("There are " + destinations.size() + " destinations."); + log.debug("Creating " + _noOfConsumers + " consumers on each destination."); + log.debug("Total number of consumers is: " + (destinations.size() * _noOfConsumers)); for (Destination destination : destinations) { @@ -914,14 +879,14 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti final int consumerNo = i; _consumer[i].setMessageListener(new MessageListener() - { - public void onMessage(Message message) { - onMessageWithConsumerNo(message, consumerNo); - } - }); + public void onMessage(Message message) + { + onMessageWithConsumerNo(message, consumerNo); + } + }); - // _log.debug("Set consumer " + i + " to listen to replies sent to destination: " + destination); + log.debug("Set consumer " + i + " to listen to replies sent to destination: " + destination); } } } @@ -931,28 +896,29 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * correlating reply may be waiting on. This is only done if the reply has a correlation id that is expected in the * replies map. * - * @param message The received message. + * @param message The received message. + * @param consumerNo The consumer number within this test pinger instance. */ public void onMessageWithConsumerNo(Message message, int consumerNo) { - // _log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo = " + consumerNo + "): called"); + // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo = " + consumerNo + "): called"); try { long now = System.nanoTime(); long timestamp = getTimestamp(message); long pingTime = now - timestamp; - // NDC.push("cons" + consumerNo); + // NDC.push("id" + instanceId + "/cons" + consumerNo); // Extract the messages correlation id. String correlationID = message.getJMSCorrelationID(); - // _log.debug("correlationID = " + correlationID); + // log.debug("correlationID = " + correlationID); - int num = message.getIntProperty("MSG_NUM"); - // _log.info("Message " + num + " received."); + // int num = message.getIntProperty("MSG_NUM"); + // log.info("Message " + num + " received."); boolean isRedelivered = message.getJMSRedelivered(); - // _log.debug("isRedelivered = " + isRedelivered); + // log.debug("isRedelivered = " + isRedelivered); if (!isRedelivered) { @@ -966,13 +932,34 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti // Restart the timeout timer on every message. perCorrelationId.timeOutStart = System.nanoTime(); - // _log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); + // log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); + + // Release waiting senders if there are some and using maxPending limit. + if ((_maxPendingSize > 0)) + { + // Decrement the count of sent but not yet received messages. + int unreceived = _unreceived.decrementAndGet(); + int unreceivedSize = + (unreceived * ((_messageSize == 0) ? 1 : _messageSize)) + / (_isPubSub ? getConsumersPerDestination() : 1); + + // log.debug("unreceived = " + unreceived); + // log.debug("unreceivedSize = " + unreceivedSize); + + // synchronized (_sendPauseMonitor) + // { + if (unreceivedSize < _maxPendingSize) + { + _sendPauseMonitor.poll(); + } + // } + } // Decrement the countdown latch. Before this point, it is possible that two threads might enter this // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block // ensures that each thread will get a unique value for the remaining messages. - long trueCount = -1; - long remainingCount = -1; + long trueCount; + long remainingCount; synchronized (trafficLight) { @@ -981,51 +968,33 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti trueCount = trafficLight.getCount(); remainingCount = trueCount - 1; - // Decrement the count of sent but not yet received messages. - int unreceived = _unreceived.decrementAndGet(); - int unreceivedSize = (unreceived * ((_messageSize == 0) ? 1 : _messageSize)); - - // Release a waiting sender if there is one. - synchronized (_sendPauseMonitor) - { - if ((_maxPendingSize > 0) && (unreceivedSize < _maxPendingSize)) - // && (_sendPauseBarrier.getNumberWaiting() == 1)) - { - // _log.debug("unreceived size estimate under limit = " + unreceivedSize); - - // Wait on the send pause barrier for the limit to be re-established. - /*try - {*/ - // _sendPauseBarrier.await(); - _sendPauseMonitor.notify(); - /*} - catch (InterruptedException e) - { - throw new RuntimeException(e); - } - catch (BrokenBarrierException e) - { - throw new RuntimeException(e); - }*/ - } - } - // NDC.push("/rem" + remainingCount); - // _log.debug("remainingCount = " + remainingCount); - // _log.debug("trueCount = " + trueCount); + // log.debug("remainingCount = " + remainingCount); + // log.debug("trueCount = " + trueCount); - // Commit on transaction batch size boundaries. At this point in time the waiting producer remains - // blocked, even on the last message. + // Commit on transaction batch size boundaries. At this point in time the waiting producer + // remains blocked, even on the last message. // Commit count is divided by noOfConsumers in p2p mode, so that each consumer only commits on // each batch boundary. For pub/sub each consumer gets every message so no division is done. + // When running in client ack mode, an ack is done instead of a commit, on the commit batch + // size boundaries. long commitCount = _isPubSub ? remainingCount : (remainingCount / _noOfConsumers); - // _log.debug("commitCount = " + commitCount); + // log.debug("commitCount = " + commitCount); if ((commitCount % _txBatchSize) == 0) { - // _log.debug("Trying commit for consumer " + consumerNo + "."); - commitTx(_consumerSession[consumerNo]); + if (_consAckMode == 2) + { + // log.debug("Doing client ack for consumer " + consumerNo + "."); + message.acknowledge(); + } + else + { + // log.debug("Trying commit for consumer " + consumerNo + "."); + commitTx(_consumerSession[consumerNo]); + // log.info("Tx committed on consumer " + consumerNo); + } } // Forward the message and remaining count to any interested chained message listener. @@ -1044,33 +1013,21 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti } else { - _log.warn("Got unexpected message with correlationId: " + correlationID); + log.warn("Got unexpected message with correlationId: " + correlationID); } } else { - _log.warn("Got redelivered message, ignoring."); + log.warn("Got redelivered message, ignoring."); } - - // Print out ping times for every message in verbose mode only. - /*if (_verbose) - { - Long timestamp = message.getLongProperty(MESSAGE_TIMESTAMP_PROPNAME); - - if (timestamp != null) - { - long diff = System.nanoTime() - timestamp; - //_log.trace("Time for round trip (nanos): " + diff); - } - }*/ } catch (JMSException e) { - _log.warn("There was a JMSException: " + e.getMessage(), e); + log.warn("There was a JMSException: " + e.getMessage(), e); } finally { - // _log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo): ending"); + // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo): ending"); // NDC.clear(); } } @@ -1084,15 +1041,17 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * @param numPings The number of ping messages to send. * @param timeout The timeout in milliseconds. * @param messageCorrelationId The message correlation id. If this is null, one is generated. + * * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait * for all prematurely. + * * @throws JMSException All underlying JMSExceptions are allowed to fall through. * @throws InterruptedException When interrupted by a timeout */ public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) - throws JMSException, InterruptedException + throws JMSException, InterruptedException { - /*_log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + /*log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ // Generate a unique correlation id to put on the messages before sending them, if one was not specified. @@ -1122,9 +1081,9 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti // Send the specifed number of messages. pingNoWaitForReply(message, numPings, messageCorrelationId); - boolean timedOut = false; - boolean allMessagesReceived = false; - int numReplies = 0; + boolean timedOut; + boolean allMessagesReceived; + int numReplies; do { @@ -1136,31 +1095,31 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti allMessagesReceived = numReplies == getExpectedNumPings(numPings); - // _log.debug("numReplies = " + numReplies); - // _log.debug("allMessagesReceived = " + allMessagesReceived); + // log.debug("numReplies = " + numReplies); + // log.debug("allMessagesReceived = " + allMessagesReceived); // Recheck the timeout condition. long now = System.nanoTime(); long lastMessageReceievedAt = perCorrelationId.timeOutStart; timedOut = (now - lastMessageReceievedAt) > (timeout * 1000000); - // _log.debug("now = " + now); - // _log.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); + // log.debug("now = " + now); + // log.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); } while (!timedOut && !allMessagesReceived); if ((numReplies < getExpectedNumPings(numPings)) && _verbose) { - _log.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); + log.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); } else if (_verbose) { - _log.info("Got all replies on id, " + messageCorrelationId); + log.info("Got all replies on id, " + messageCorrelationId); } // commitTx(_consumerSession); - // _log.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); + // log.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); return numReplies; } @@ -1179,11 +1138,12 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * @param message The message to send. * @param numPings The number of pings to send. * @param messageCorrelationId A correlation id to place on all messages sent. + * * @throws JMSException All underlying JMSExceptions are allowed to fall through. */ public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException { - /*_log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings + /*log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ if (message == null) @@ -1201,9 +1161,6 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti // Send all of the ping messages. for (int i = 0; i < numPings; i++) { - // Reset the committed flag to indicate that there may be uncommitted messages. - committed = false; - // Re-timestamp the message. // message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); @@ -1213,7 +1170,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti // Spew out per message timings on every message sonly in verbose mode. /*if (_verbose) { - _log.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); + log.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); }*/ } @@ -1232,104 +1189,168 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * * @param i The count of messages sent so far in a loop of multiple calls to this send method. * @param message The message to send. + * * @return true if the messages were committed, false otherwise. + * * @throws JMSException All underlyiung JMSExceptions are allowed to fall through. */ protected boolean sendMessage(int i, Message message) throws JMSException { - // _log.debug("protected boolean sendMessage(int i = " + i + ", Message message): called"); - // _log.debug("_txBatchSize = " + _txBatchSize); + try + { + NDC.push("id" + instanceId + "/prod"); - // Round robin the destinations as the messages are sent. - Destination destination = _pingDestinations.get(i % _pingDestinations.size()); + // log.debug("protected boolean sendMessage(int i = " + i + ", Message message): called"); + // log.debug("_txBatchSize = " + _txBatchSize); - // Prompt the user to kill the broker when doing failover testing. - if (_failBeforeSend) - { - if (_failOnce) - { - _failBeforeSend = false; - } + // Round robin the destinations as the messages are sent. + Destination destination = _pingDestinations.get(i % _pingDestinations.size()); - // _log.trace("Failing Before Send"); - waitForUser(KILL_BROKER_PROMPT); - } + // Prompt the user to kill the broker when doing failover testing. + _failBeforeSend = waitForUserToPromptOnFailure(_failBeforeSend); - // If necessary, wait until the max pending message size comes within its limit. - synchronized (_sendPauseMonitor) - { - while ((_maxPendingSize > 0)) - { - // Get the size estimate of sent but not yet received messages. - int unreceived = _unreceived.get(); - int unreceivedSize = (unreceived * ((_messageSize == 0) ? 1 : _messageSize)); + // Get the test setup for the correlation id. + String correlationID = message.getJMSCorrelationID(); + PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); - if (unreceivedSize > _maxPendingSize) + // If necessary, wait until the max pending message size comes within its limit. + if (_maxPendingSize > 0) + { + synchronized (_sendPauseMonitor) { - // _log.debug("unreceived size estimate over limit = " + unreceivedSize); + // Used to keep track of the number of times that send has to wait. + int numWaits = 0; - // Wait on the send pause barrier for the limit to be re-established. - try - { - // _sendPauseBarrier.await(); - _sendPauseMonitor.wait(1000); - } - catch (InterruptedException e) + // The maximum number of waits before the test gives up and fails. This has been chosen to correspond with + // the test timeout. + int waitLimit = (int) (TIMEOUT_DEFAULT / 10000); + + while (true) { - // Restore the interrupted status - Thread.currentThread().interrupt(); - throw new RuntimeException(e); + // Get the size estimate of sent but not yet received messages. + int unreceived = _unreceived.get(); + int unreceivedSize = + (unreceived * ((_messageSize == 0) ? 1 : _messageSize)) + / (_isPubSub ? getConsumersPerDestination() : 1); + + // log.debug("unreceived = " + unreceived); + // log.debug("unreceivedSize = " + unreceivedSize); + // log.debug("_maxPendingSize = " + _maxPendingSize); + + if (unreceivedSize > _maxPendingSize) + { + // log.debug("unreceived size estimate over limit = " + unreceivedSize); + + // Fail the test if the send has had to wait more than the maximum allowed number of times. + if (numWaits > waitLimit) + { + String errorMessage = + "Send has had to wait for the unreceivedSize (" + unreceivedSize + + ") to come below the maxPendingSize (" + _maxPendingSize + ") more that " + waitLimit + + " times."; + log.warn(errorMessage); + throw new RuntimeException(errorMessage); + } + + // Wait on the send pause barrier for the limit to be re-established. + try + { + long start = System.nanoTime(); + // _sendPauseMonitor.wait(10000); + _sendPauseMonitor.offer(new Object(), 10000, TimeUnit.MILLISECONDS); + long end = System.nanoTime(); + + // Count the wait only if it was for > 99% of the requested wait time. + if (((float) (end - start) / (float) (10000 * 1000000L)) > 0.99) + { + numWaits++; + } + } + catch (InterruptedException e) + { + // Restore the interrupted status + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + } + else + { + break; + } } - /*catch (BrokenBarrierException e) - { - throw new RuntimeException(e); - }*/ - } - else - { - break; } } - } - // Send the message either to its round robin destination, or its default destination. - if (destination == null) - { - int num = numSent.incrementAndGet(); - message.setIntProperty("MSG_NUM", num); + // Send the message either to its round robin destination, or its default destination. + // int num = numSent.incrementAndGet(); + // message.setIntProperty("MSG_NUM", num); setTimestamp(message); - _producer.send(message); - // _log.info("Message " + num + " sent."); - } - else - { - int num = numSent.incrementAndGet(); - message.setIntProperty("MSG_NUM", num); - setTimestamp(message); - _producer.send(destination, message); - // _log.info("Message " + num + " sent."); - } - // Increase the unreceived size, this may actually happen aftern the message is recevied. - _unreceived.getAndIncrement(); + if (destination == null) + { + _producer.send(message); + } + else + { + _producer.send(destination, message); + } + + // Increase the unreceived size, this may actually happen after the message is received. + // The unreceived size is incremented by the number of consumers that will get a copy of the message, + // in pub/sub mode. + if (_maxPendingSize > 0) + { + int newUnreceivedCount = _unreceived.addAndGet(_isPubSub ? getConsumersPerDestination() : 1); + // log.debug("newUnreceivedCount = " + newUnreceivedCount); + } - // Apply message rate throttling if a rate limit has been set up. - if (_rateLimiter != null) + // Apply message rate throttling if a rate limit has been set up. + if (_rateLimiter != null) + { + _rateLimiter.throttle(); + } + + // Call commit every time the commit batch size is reached. + boolean committed = false; + + // Commit on every transaction batch size boundary. Here i + 1 is the count of actual messages sent. + if (((i + 1) % _txBatchSize) == 0) + { + // log.debug("Trying commit on producer session."); + committed = commitTx(_producerSession); + } + + return committed; + } + finally { - _rateLimiter.throttle(); + NDC.clear(); } + } - // Call commit every time the commit batch size is reached. - boolean committed = false; - - // Commit on every transaction batch size boundary. Here i + 1 is the count of actual messages sent. - if (((i + 1) % _txBatchSize) == 0) + /** + * If the specified fail flag is set, this method waits for the user to cause a failure and then indicate to the + * test that the failure has occurred, before the method returns. + * + * @param failFlag The fail flag to test. + * + * @return The new value for the fail flag. If the {@link #_failOnce} flag is set, then each fail flag is only + * used once, then reset. + */ + private boolean waitForUserToPromptOnFailure(boolean failFlag) + { + if (failFlag) { - // _log.debug("Trying commit on producer session."); - committed = commitTx(_producerSession); + if (_failOnce) + { + failFlag = false; + } + + // log.debug("Failing Before Send"); + waitForUser(KILL_BROKER_PROMPT); } - return committed; + return failFlag; } /** @@ -1351,12 +1372,12 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti catch (JMSException e) { _publish = false; - // _log.debug("There was a JMSException: " + e.getMessage(), e); + // log.debug("There was a JMSException: " + e.getMessage(), e); } catch (InterruptedException e) { _publish = false; - // _log.debug("There was an interruption: " + e.getMessage(), e); + // log.debug("There was an interruption: " + e.getMessage(), e); } } @@ -1371,9 +1392,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti _chainedMessageListener = messageListener; } - /** - * Removes any chained message listeners from this pinger. - */ + /** Removes any chained message listeners from this pinger. */ public void removeChainedMessageListener() { _chainedMessageListener = null; @@ -1385,32 +1404,61 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * @param replyQueue The reply-to destination for the message. * @param messageSize The desired size of the message in bytes. * @param persistent true if the message should use persistent delivery, false otherwise. + * * @return A freshly generated test message. + * * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. */ public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException { - ObjectMessage msg = TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); - - // Timestamp the message in nanoseconds. - - // setTimestamp(msg); - - return msg; + // return TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); + return TestUtils.createTestMessageOfSize(_producerSession, messageSize); } + /** + * Sets the current time in nanoseconds as the timestamp on the message. + * + * @param msg The message to timestamp. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ protected void setTimestamp(Message msg) throws JMSException { + /*if (((AMQSession)_producerSession).isStrictAMQP()) + { + ((AMQMessage)msg).setTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME), System.nanoTime()); + } + else + {*/ msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); + // } } + /** + * Extracts the nanosecond timestamp from a message. + * + * @param msg The message to extract the time stamp from. + * + * @return The timestamp in nanos. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ protected long getTimestamp(Message msg) throws JMSException { + /*if (((AMQSession)_producerSession).isStrictAMQP()) + { + Long value = ((AMQMessage)msg).getTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME)); + + return (value == null) ? 0L : value; + } + else + {*/ return msg.getLongProperty(PingPongProducer.MESSAGE_TIMESTAMP_PROPNAME); + // } } /** - * Stops the ping loop by clearing the publish flag. The current loop will complete before it notices that this flag + * Stops the ping loop by clearing the publish flag. The current loop will complete when it notices that this flag * has been cleared. */ public void stop() @@ -1418,19 +1466,26 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti _publish = false; } + /** + * Starts the producer and consumer connections. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ public void start() throws JMSException { + // log.debug("public void start(): called"); + _connection.start(); + // log.debug("Producer started."); for (int i = 0; i < _noOfConsumers; i++) { _consumerConnection[i].start(); + // log.debug("Consumer " + i + " started."); } } - /** - * Implements a ping loop that repeatedly pings until the publish flag becomes false. - */ + /** Implements a ping loop that repeatedly pings until the publish flag becomes false. */ public void run() { // Keep running until the publish flag is cleared. @@ -1448,7 +1503,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ public void onException(JMSException e) { - // _log.debug("public void onException(JMSException e = " + e + "): called", e); + // log.debug("public void onException(JMSException e = " + e + "): called", e); _publish = false; } @@ -1461,37 +1516,39 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti public Thread getShutdownHook() { return new Thread(new Runnable() - { - public void run() - { - stop(); - } - }); + { + public void run() + { + stop(); + } + }); } /** - * Closes the pingers connection. + * Closes all of the producer and consumer connections. * * @throws JMSException All JMSException are allowed to fall through. */ public void close() throws JMSException { - // _log.debug("public void close(): called"); + // log.debug("public void close(): called"); try { if (_connection != null) { + // log.debug("Before close producer connection."); _connection.close(); - // _log.debug("Close connection."); + // log.debug("Closed producer connection."); } for (int i = 0; i < _noOfConsumers; i++) { if (_consumerConnection[i] != null) { + // log.debug("Before close consumer connection " + i + "."); _consumerConnection[i].close(); - // _log.debug("Closed consumer connection."); + // log.debug("Closed consumer connection " + i + "."); } } } @@ -1511,86 +1568,61 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti /** * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not a * transactional controlSession, this method does nothing (unless the failover after send flag is set). - *

    + * *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit is * applied. This flag applies whether the pinger is transactional or not. - *

    + * *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the commit * is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker after the * commit is applied. These flags will only apply if using a transactional pinger. * * @param session The controlSession to commit + * * @return true if the controlSession was committed, false if it was not. + * * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + * * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit * method, because commits only apply to transactional pingers, but fail after send applied to transactional and * non-transactional alike. */ protected boolean commitTx(Session session) throws JMSException { - // _log.debug("protected void commitTx(Session session): called"); + // log.debug("protected void commitTx(Session session): called"); boolean committed = false; - // _log.trace("Batch time reached"); - if (_failAfterSend) - { - // _log.trace("Batch size reached"); - if (_failOnce) - { - _failAfterSend = false; - } - - // _log.trace("Failing After Send"); - waitForUser(KILL_BROKER_PROMPT); - } + _failAfterSend = waitForUserToPromptOnFailure(_failAfterSend); if (session.getTransacted()) { - // _log.debug("Session is transacted."); + // log.debug("Session is transacted."); try { - if (_failBeforeCommit) - { - if (_failOnce) - { - _failBeforeCommit = false; - } - - // _log.trace("Failing Before Commit"); - waitForUser(KILL_BROKER_PROMPT); - } + _failBeforeCommit = waitForUserToPromptOnFailure(_failBeforeCommit); long start = System.nanoTime(); session.commit(); committed = true; - // _log.debug("Time taken to commit :" + ((System.nanoTime() - start) / 1000000f) + " ms"); + // log.debug("Time taken to commit :" + ((System.nanoTime() - start) / 1000000f) + " ms"); - if (_failAfterCommit) - { - if (_failOnce) - { - _failAfterCommit = false; - } + _failAfterCommit = waitForUserToPromptOnFailure(_failAfterCommit); - // _log.trace("Failing After Commit"); - waitForUser(KILL_BROKER_PROMPT); - } - - // _log.debug("Session Commited."); + // log.debug("Session Commited."); } catch (JMSException e) { - // _log.debug("JMSException on commit:" + e.getMessage(), e); + // log.debug("JMSException on commit:" + e.getMessage(), e); + try { session.rollback(); - // _log.debug("Message rolled back."); + // log.debug("Message rolled back."); } catch (JMSException jmse) { - // _log.debug("JMSE on rollback:" + jmse.getMessage(), jmse); + // log.debug("JMSE on rollback:" + jmse.getMessage(), jmse); // Both commit and rollback failed. Throw the rollback exception. throw jmse; @@ -1636,13 +1668,14 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * Calculates how many pings are expected to be received for the given number sent. * * @param numpings The number of pings that will be sent. + * * @return The number that should be received, for the test to pass. */ public int getExpectedNumPings(int numpings) { - // _log.debug("public int getExpectedNumPings(int numpings = " + numpings + "): called"); + // log.debug("public int getExpectedNumPings(int numpings = " + numpings + "): called"); - // _log.debug("Each ping will be received by " + (_isPubSub ? getConsumersPerDestination() : 1) + " consumers."); + // log.debug("Each ping will be received by " + (_isPubSub ? getConsumersPerDestination() : 1) + " consumers."); return numpings * (_isPubSub ? getConsumersPerDestination() : 1); } @@ -1652,7 +1685,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * PingPongProducer#onMessageWithConsumerNo} method is called, the chained listener set through the {@link * PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected count of * messages with that correlation id. - *

    + * *

    Provided only one pinger is producing messages with that correlation id, the chained listener will always be * given unique message counts. It will always be called while the producer waiting for all messages to arrive is * still blocked. @@ -1666,6 +1699,7 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti * @param message The newly arrived message. * @param remainingCount The number of messages left to complete the test. * @param latency The nanosecond latency of the message. + * * @throws JMSException Any JMS exceptions is allowed to fall through. */ public void onMessage(Message message, int remainingCount, long latency) throws JMSException; @@ -1677,14 +1711,10 @@ public class PingPongProducer implements Runnable /*, MessageListener*/, Excepti */ protected static class PerCorrelationId { - /** - * Holds a countdown on number of expected messages. - */ + /** Holds a countdown on number of expected messages. */ CountDownLatch trafficLight; - /** - * Holds the last timestamp that the timeout was reset to. - */ + /** Holds the last timestamp that the timeout was reset to. */ Long timeOutStart; } } -- cgit v1.2.1 From 36a2e847b30095fe69f0bd2f2b70cd2676c97078 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Mon, 12 Nov 2007 18:08:15 +0000 Subject: Added a new set of performance tests which is more focused on getting the throughput. The producers and consumers can be run from separate machines. There is no pass/fail, it merely records message count, memory etc at periodic intervals and prints a summary at the the end of the test. Since there are periodic entries, you could identify the rough time time it crashed and memory consumption etc. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@594239 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/client/perf/ConnectionUtility.java | 50 +++++++ .../org/apache/qpid/client/perf/JMSConsumer.java | 101 +++++++++++++ .../org/apache/qpid/client/perf/JMSProducer.java | 96 ++++++++++++ .../qpid/client/perf/MessageConsumerTest.java | 162 +++++++++++++++++++++ .../qpid/client/perf/MessageProducerTest.java | 159 ++++++++++++++++++++ .../java/org/apache/qpid/client/perf/Options.java | 105 +++++++++++++ 6 files changed, 673 insertions(+) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/ConnectionUtility.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/ConnectionUtility.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/ConnectionUtility.java new file mode 100644 index 0000000000..133ef5f854 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/ConnectionUtility.java @@ -0,0 +1,50 @@ +package org.apache.qpid.client.perf; + +import javax.naming.InitialContext; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConnectionUtility +{ + private static final Logger _logger = LoggerFactory.getLogger(ConnectionUtility.class); + + private InitialContext _initialContext; + private AMQConnectionFactory _connectionFactory; + + private static ConnectionUtility _instance = new ConnectionUtility(); + + public static ConnectionUtility getInstance() + { + return _instance; + } + + private InitialContext getInitialContext() throws Exception + { + _logger.info("get InitialContext"); + if (_initialContext == null) + { + _initialContext = new InitialContext(); + } + return _initialContext; + } + + private AMQConnectionFactory getConnectionFactory() throws Exception + { + _logger.info("get ConnectionFactory"); + if (_connectionFactory == null) + { + _connectionFactory = (AMQConnectionFactory) getInitialContext().lookup("local"); + } + return _connectionFactory; + } + + public AMQConnection getConnection() throws Exception + { + _logger.info("get Connection"); + return (AMQConnection)getConnectionFactory().createConnection(); + } + +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java new file mode 100644 index 0000000000..6b6a8a509c --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java @@ -0,0 +1,101 @@ +package org.apache.qpid.client.perf; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JMSConsumer implements Runnable +{ + private static final Logger _logger = LoggerFactory.getLogger(JMSConsumer.class); + + private String _id; + private Connection _connection; + private Session _session; + private MessageConsumer _consumer; + private Destination _destination; + private boolean _transacted; + private int _ackMode = Session.AUTO_ACKNOWLEDGE; + private AtomicBoolean _run = new AtomicBoolean(true); + private long _currentMsgCount; + + /* Not implementing transactions for first phase */ + public JMSConsumer(String id,Connection connection, Destination destination,boolean transacted,int ackMode) throws Exception + { + _id = id; + _connection = connection; + _destination = destination; + _transacted = transacted; + _ackMode = ackMode; + } + + public void run() + { + _run.set(true); + + try + { + _session = _connection.createSession(_transacted, _ackMode); + _consumer = _session.createConsumer(_destination); + } + catch(Exception e) + { + _logger.error("Error Setting up JMSProducer:"+ _id, e); + } + + while (_run.get()) + { + try + { + BytesMessage msg = (BytesMessage)_consumer.receive(); + if (msg != null) + { + long msgId = Integer.parseInt(msg.getJMSCorrelationID()); + if (_currentMsgCount+1 != msgId) + { + _logger.error("Error : Message received out of order in JMSConsumer:" + _id + " message id was " + msgId); + } + _currentMsgCount ++; + } + } + catch(Exception e) + { + _logger.error("Error Receiving message from JMSConsumer:" + _id, e); + } + } + try + { + _session.close(); + _connection.close(); + } + catch(Exception e) + { + _logger.error("Error Closing JMSConsumer:"+ _id, e); + } + } + + public void stopConsuming() + { + _run.set(false); + } + + public String getId() + { + return _id; + } + + /* Not worried about synchronizing as accuracy here is not that important. + * So if this method is invoked the count maybe off by a few digits. + * But when the test stops, this will always return the proper count. + */ + public long getCurrentMessageCount() + { + return _currentMsgCount; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java new file mode 100644 index 0000000000..c9c5b2b308 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java @@ -0,0 +1,96 @@ +package org.apache.qpid.client.perf; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.qpid.client.message.TestMessageFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JMSProducer implements Runnable +{ + private static final Logger _logger = LoggerFactory.getLogger(JMSProducer.class); + + private String _id; + private int _messageSize; + private Connection _connection; + private Session _session; + private MessageProducer _producer; + private Destination _destination; + private BytesMessage _payload; + private boolean _transacted; + private int _ackMode = Session.AUTO_ACKNOWLEDGE; + private AtomicBoolean _run = new AtomicBoolean(true); + private long _currentMsgCount; + + /* Not implementing transactions for first phase */ + public JMSProducer(String id,Connection connection, Destination destination,int messageSize, boolean transacted) throws Exception + { + _id = id; + _connection = connection; + _destination = destination; + _messageSize = messageSize; + _transacted = transacted; + } + + public void run() + { + try + { + _session = _connection.createSession(_transacted, _ackMode); + _payload = TestMessageFactory.newBytesMessage(_session, _messageSize); + _producer = _session.createProducer(_destination); + } + catch(Exception e) + { + _logger.error("Error Setting up JMSProducer:"+ _id, e); + } + + while (_run.get()) + { + try + { + _payload.setJMSCorrelationID(String.valueOf(_currentMsgCount+1)); + _producer.send(_payload); + _currentMsgCount ++; + } + catch(Exception e) + { + _logger.error("Error Sending message from JMSProducer:" + _id, e); + } + } + try + { + _session.close(); + _connection.close(); + } + catch(Exception e) + { + _logger.error("Error Closing JMSProducer:"+ _id, e); + } + } + + public void stopProducing() + { + _run.set(false); + } + + public String getId() + { + return _id; + } + + /* Not worried about synchronizing as accuracy here is not that important. + * So if this method is invoked the count maybe off by a few digits. + * But when the test stops, this will always return the proper count. + */ + public long getCurrentMessageCount() + { + return _currentMsgCount; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java new file mode 100644 index 0000000000..4d6923f0dd --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java @@ -0,0 +1,162 @@ +package org.apache.qpid.client.perf; + +import java.io.FileWriter; +import java.io.RandomAccessFile; +import java.sql.Date; +import java.text.SimpleDateFormat; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Session; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQTopic; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MessageConsumerTest extends Options implements Runnable +{ + private static final Logger _logger = LoggerFactory.getLogger(MessageConsumerTest.class); + private SimpleDateFormat df = new SimpleDateFormat("h:mm a"); + + private Map _consumers = new ConcurrentHashMap(); + private int _count; + String _logFileName; + private long _gracePeriod = 5 * 60 * 1000; + long _startTime; + long totalMsgCount; + + public void start() throws Exception + { + this.parseOptions(); + boolean useSameDest = true; + _logFileName = _logFilePath + "/MessageConsumerTest_" + System.currentTimeMillis(); + + // use each destination with a different producer + if (_producerCount == destArray.length) + { + useSameDest = false; + } + for (;_count < _producerCount;_count++) + { + createAndStartProducer(useSameDest?destArray[0]:destArray[_count]); + } + } + + private void createAndStartProducer(String routingKey)throws Exception + { + AMQConnection con = ConnectionUtility.getInstance().getConnection(); + con.start(); + Destination dest = new AMQTopic(con,routingKey); + JMSConsumer prod = new JMSConsumer(String.valueOf(_count),(Connection)con, dest, _transacted,Session.AUTO_ACKNOWLEDGE); + Thread t = new Thread(prod); + t.setName("JMSConsumer-"+_count); + t.start(); + _consumers.put(_count, prod); + } + + private void startTimerThread() + { + Thread t = new Thread(this); + t.setName("MessageConsumerTest-TimerThread"); + t.start(); + } + + public void run() + { + boolean run = true; + _startTime = System.currentTimeMillis(); + try + { + while(run) + { + Thread.sleep(_logDuration); + runReaper(false); + + if(System.currentTimeMillis() + _gracePeriod - _startTime > _expiry ) + { + // time to stop the test. + for (Integer id : _consumers.keySet()) + { + JMSConsumer consumer = _consumers.get(id); + consumer.stopConsuming(); + } + runReaper(true); + run = false; + } + } + } + catch (InterruptedException e) + { + _logger.error("The timer thread exited",e); + } + } + + public void runReaper(boolean printSummary) + { + try + { + FileWriter _logFile = new FileWriter(_logFileName + ".csv",true); + for (Integer id : _consumers.keySet()) + { + JMSConsumer prod = _consumers.get(id); + StringBuffer buf = new StringBuffer("JMSConsumer(").append(prod.getId()).append("),"); + Date d = new Date(System.currentTimeMillis()); + buf.append(df.format(d)).append(","); + buf.append(d.getTime()).append(","); + buf.append(prod.getCurrentMessageCount()).append("\n"); + _logFile.write(buf.toString()); + totalMsgCount = totalMsgCount + prod.getCurrentMessageCount(); + } + _logFile.close(); + + FileWriter _memoryLog = new FileWriter(_logFileName + "_memory.csv",true); + StringBuffer buf = new StringBuffer("JMSConsumer,"); + Date d = new Date(System.currentTimeMillis()); + buf.append(df.format(d)).append(","); + buf.append(d.getTime()).append(","); + buf.append(totalMsgCount).append(","); + buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); + _memoryLog.write(buf.toString()); + _memoryLog.close(); + if (printSummary) + { + double totaltime = (d.getTime() - _startTime)*1000; // trying to get a per sec rate + double dCount = totalMsgCount; + double ratio = dCount/totaltime; + FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); + buf = new StringBuffer("MessageConsumerTest \n Test started at : "); + buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); + d = new Date(System.currentTimeMillis()); + buf.append(df.format(d)).append("\n Total Time taken (ms):"); + buf.append(totaltime).append("\n Total messages received:"); + buf.append(totalMsgCount).append("\n Consumer rate:"); + buf.append(ratio).append("\n"); + _summaryLog.write(buf.toString()); + System.out.println("---------- Test Ended -------------"); + _summaryLog.close(); + } + } + catch(Exception e) + { + _logger.error("Error printing info to the log file",e); + } + } + + public static void main(String[] args) + { + try + { + MessageConsumerTest test = new MessageConsumerTest(); + test.start(); + test.startTimerThread(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java new file mode 100644 index 0000000000..b0caa45845 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java @@ -0,0 +1,159 @@ +package org.apache.qpid.client.perf; + +import java.io.FileWriter; +import java.sql.Date; +import java.text.SimpleDateFormat; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.jms.Connection; +import javax.jms.Destination; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQTopic; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MessageProducerTest extends Options implements Runnable +{ + private static final Logger _logger = LoggerFactory.getLogger(MessageProducerTest.class); + private SimpleDateFormat df = new SimpleDateFormat("h:mm a"); + + private Map _producers = new ConcurrentHashMap(); + private int _count; + String _logFileName; + long _startTime; + long totalMsgCount; + + public void start() throws Exception + { + this.parseOptions(); + boolean useSameDest = true; + _logFileName = _logFilePath + "/MessageProducerTest_" + System.currentTimeMillis(); + + // use each destination with a different producer + if (_producerCount == destArray.length) + { + useSameDest = false; + } + for (;_count < _producerCount;_count++) + { + createAndStartProducer(useSameDest?destArray[0]:destArray[_count]); + } + } + + private void createAndStartProducer(String routingKey)throws Exception + { + AMQConnection con = ConnectionUtility.getInstance().getConnection(); + con.start(); + Destination dest = new AMQTopic(con,routingKey); + JMSProducer prod = new JMSProducer(String.valueOf(_count),(Connection)con, dest,_messageSize, _transacted); + Thread t = new Thread(prod); + t.setName("JMSProducer-"+_count); + t.start(); + _producers.put(_count, prod); + } + + private void startTimerThread() + { + Thread t = new Thread(this); + t.setName("MessageProducerTest-TimerThread"); + t.start(); + } + + public void run() + { + boolean run = true; + _startTime = System.currentTimeMillis(); + try + { + while(run) + { + Thread.sleep(_logDuration); + runReaper(false); + + if(System.currentTimeMillis() - _startTime > _expiry ) + { + // time to stop the test. + for (Integer id : _producers.keySet()) + { + JMSProducer prod = _producers.get(id); + prod.stopProducing(); + } + runReaper(true); + run = false; + } + } + } + catch (InterruptedException e) + { + _logger.error("The timer thread exited",e); + } + } + + public void runReaper(boolean printSummary) + { + try + { + FileWriter _logFile = new FileWriter(_logFileName + ".csv",true); + for (Integer id : _producers.keySet()) + { + JMSProducer prod = _producers.get(id); + StringBuffer buf = new StringBuffer("JMSProducer(").append(prod.getId()).append("),"); + Date d = new Date(System.currentTimeMillis()); + buf.append(df.format(d)).append(","); + buf.append(d.getTime()).append(","); + buf.append(prod.getCurrentMessageCount()).append("\n"); + _logFile.write(buf.toString()); + totalMsgCount = totalMsgCount + prod.getCurrentMessageCount(); + } + _logFile.close(); + + FileWriter _memoryLog = new FileWriter(_logFileName + "_memory.csv",true); + StringBuffer buf = new StringBuffer("JMSProducer,"); + Date d = new Date(System.currentTimeMillis()); + buf.append(df.format(d)).append(","); + buf.append(d.getTime()).append(","); + buf.append(totalMsgCount).append(","); + buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); + _memoryLog.write(buf.toString()); + _memoryLog.close(); + if (printSummary) + { + double totaltime = (d.getTime() - _startTime)*1000; // trying to get a per sec rate + double dCount = totalMsgCount; + double ratio = dCount/totaltime; + FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); + buf = new StringBuffer("MessageProducerTest \n Test started at : "); + buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); + d = new Date(System.currentTimeMillis()); + buf.append(df.format(d)).append("\n Total Time taken (ms):"); + buf.append(totaltime).append("\n Total messages sent:"); + buf.append(totalMsgCount).append("\n Producer rate:"); + buf.append(ratio).append("\n"); + _summaryLog.write(buf.toString()); + System.out.println("---------- Test Ended -------------"); + _summaryLog.close(); + } + } + catch(Exception e) + { + _logger.error("Error printing info to the log file",e); + } + } + + public static void main(String[] args) + { + try + { + MessageProducerTest test = new MessageProducerTest(); + test.start(); + test.startTimerThread(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java new file mode 100644 index 0000000000..1bcf04ae4a --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java @@ -0,0 +1,105 @@ +package org.apache.qpid.client.perf; + +public class Options +{ + int _messageSize; + boolean _transacted; + String[] destArray; + int _producerCount; + int _consumerCount; + long _expiry; + long _logDuration; + String _logFilePath; + + /** + * System props + * -DmessageSize + * -Dtransacted + * -DproducerCount + * -DconsumerCount + * -Ddestinations + * -DlogFilePath + * -Duration=1H,30M,10S + * -DlogDuration=10 in mins + */ + public void parseOptions() + { + _messageSize = Integer.parseInt(System.getProperty("messageSize","100")); + _transacted = false; + String destinations = System.getProperty("destinations"); + destArray = destinations.split(","); + _producerCount = Integer.parseInt(System.getProperty("producerCount","1")); + _consumerCount = Integer.parseInt(System.getProperty("consumerCount","1")); + _logDuration = Long.parseLong(System.getProperty("logDuration","10")); + _logDuration = _logDuration*1000*60; + _logFilePath = System.getProperty("logFilePath"); + _expiry = getExpiry(); + + System.out.println("============= Test Data ==================="); + System.out.println("Total no of producers : " + _producerCount); + System.out.println("Total no of consumer : " + _consumerCount); + System.out.println("Log Frequency in mins : " + _logDuration/(1000*60)); + System.out.println("Log file path : " + _logFilePath); + System.out.println("Test Duration : " + printTestDuration()); + System.out.println("============= /Test Data ==================="); + } + + private String printTestDuration() + { + StringBuffer buf = new StringBuffer(); + int hours = (int)_expiry/(60*60*1000); + int mins = (int)_expiry/(60*1000); + int secs = (int)_expiry/1000; + if (hours > 0) + { + buf.append(hours).append(" hours, "); + } + if (mins > 0) + { + buf.append(mins).append(" mins, "); + } + if (secs > 0) + { + buf.append(secs).append(" secs"); + } + + return buf.toString(); + } + + private long getExpiry() + { + // default is 30 mins + long time = 0; + String s = System.getProperty("duration"); + if(s != null) + { + String[] temp = s.split(","); + for (String st:temp) + { + if(st.indexOf("H")>0) + { + int hour = Integer.parseInt(st.substring(0,st.indexOf("H"))); + time = time + hour * 60 * 60 * 1000; + } + else if(st.indexOf("M")>0) + { + int min = Integer.parseInt(st.substring(0,st.indexOf("M"))); + time = time + min * 60 * 1000; + } + else if(st.indexOf("S")>0) + { + int sec = Integer.parseInt(st.substring(0,st.indexOf("S"))); + time = time + sec * 1000; + } + + } + } + if (time == 0) + { + time = 30 * 60 * 1000; + } + + return time; + } + +} -- cgit v1.2.1 From f1aff365de18efc47b093a8556c81d8cfca8bf46 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Tue, 13 Nov 2007 00:14:13 +0000 Subject: modified to collect memory stats before the test. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@594360 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java | 1 + .../src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java | 1 + 2 files changed, 2 insertions(+) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java index 4d6923f0dd..e220aec9e1 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java @@ -68,6 +68,7 @@ public class MessageConsumerTest extends Options implements Runnable { boolean run = true; _startTime = System.currentTimeMillis(); + runReaper(false); try { while(run) diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java index b0caa45845..794031f346 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java @@ -65,6 +65,7 @@ public class MessageProducerTest extends Options implements Runnable { boolean run = true; _startTime = System.currentTimeMillis(); + runReaper(false); try { while(run) -- cgit v1.2.1 From 20f5e0b2504bddaecb396f602e0a8a618a525ea9 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Tue, 13 Nov 2007 04:41:57 +0000 Subject: Fixed errors in the calculation git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@594429 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/client/perf/JMSConsumer.java | 7 ++++--- .../src/main/java/org/apache/qpid/client/perf/JMSProducer.java | 1 + .../main/java/org/apache/qpid/client/perf/MessageConsumerTest.java | 4 ++-- .../main/java/org/apache/qpid/client/perf/MessageProducerTest.java | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java index 6b6a8a509c..635fcaa248 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java @@ -57,10 +57,10 @@ public class JMSConsumer implements Runnable if (msg != null) { long msgId = Integer.parseInt(msg.getJMSCorrelationID()); - if (_currentMsgCount+1 != msgId) + /*if (_currentMsgCount+1 != msgId) { - _logger.error("Error : Message received out of order in JMSConsumer:" + _id + " message id was " + msgId); - } + _logger.error("Error : Message received out of order in JMSConsumer:" + _id + " message id was " + msgId + " expected: " + _currentMsgCount+1); + }*/ _currentMsgCount ++; } } @@ -83,6 +83,7 @@ public class JMSConsumer implements Runnable public void stopConsuming() { _run.set(false); + System.out.println("Producer received notification to stop"); } public String getId() diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java index c9c5b2b308..60913795ba 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java @@ -78,6 +78,7 @@ public class JMSProducer implements Runnable public void stopProducing() { _run.set(false); + System.out.println("Producer received notification to stop"); } public String getId() diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java index e220aec9e1..99659fed44 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java @@ -124,9 +124,9 @@ public class MessageConsumerTest extends Options implements Runnable _memoryLog.close(); if (printSummary) { - double totaltime = (d.getTime() - _startTime)*1000; // trying to get a per sec rate + double totaltime = d.getTime() - _startTime; double dCount = totalMsgCount; - double ratio = dCount/totaltime; + double ratio = (dCount/totaltime)*1000; FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); buf = new StringBuffer("MessageConsumerTest \n Test started at : "); buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java index 794031f346..b0ea28292d 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java @@ -121,9 +121,9 @@ public class MessageProducerTest extends Options implements Runnable _memoryLog.close(); if (printSummary) { - double totaltime = (d.getTime() - _startTime)*1000; // trying to get a per sec rate + double totaltime = d.getTime() - _startTime; double dCount = totalMsgCount; - double ratio = dCount/totaltime; + double ratio = (dCount/totaltime)*1000; FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); buf = new StringBuffer("MessageProducerTest \n Test started at : "); buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); -- cgit v1.2.1 From 0ce22df53e824db1be3987a966ac56f99c4bb9b6 Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Tue, 13 Nov 2007 10:57:46 +0000 Subject: Changed to use initial context helper git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@594482 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/requestreply/PingPongProducer.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index c3689151d2..da6d6eb7d0 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -669,12 +669,9 @@ public class PingPongProducer implements Runnable, ExceptionListener // _log.debug("protected void createConnection(String clientID = " + clientID + "): called"); // _log.debug("Creating a connection for the message producer."); - File propsFile = new File(_fileProperties); - InputStream is = new FileInputStream(propsFile); - Properties properties = new Properties(); - properties.load(is); + - Context context = new InitialContext(properties); + Context context = InitialContextHelper.getInitialContext(_fileProperties); ConnectionFactory factory = (ConnectionFactory) context.lookup(_factoryName); _connection = factory.createConnection(_username, _password); -- cgit v1.2.1 From ed240c2fd6bceb51fa8ec93ad1088b4734f20ca2 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Tue, 13 Nov 2007 16:46:52 +0000 Subject: Fixed an error in the printTestDuration method git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@594577 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/client/perf/Options.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java index 1bcf04ae4a..ee22b6804b 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java @@ -47,16 +47,22 @@ public class Options private String printTestDuration() { StringBuffer buf = new StringBuffer(); - int hours = (int)_expiry/(60*60*1000); - int mins = (int)_expiry/(60*1000); - int secs = (int)_expiry/1000; + long temp = _expiry; + int hours = (int)temp/(60*60*1000); + temp = temp -hours*60*60*1000; + + int mins = (int)(temp)/(60*1000); + temp = temp -mins*60*1000; + + int secs = (int)temp/1000; + if (hours > 0) { - buf.append(hours).append(" hours, "); + buf.append(hours).append(" hours "); } if (mins > 0) { - buf.append(mins).append(" mins, "); + buf.append(mins).append(" mins "); } if (secs > 0) { -- cgit v1.2.1 From 613ceb29988f1c5d44ac41510a0fa4424fb04142 Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Wed, 14 Nov 2007 09:38:05 +0000 Subject: Added distinction between sync and async consumers git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@594814 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/client/perf/JMSAsyncConsumer.java | 91 +++++++++++++++ .../org/apache/qpid/client/perf/JMSConsumer.java | 124 +++++---------------- .../apache/qpid/client/perf/JMSSyncConsumer.java | 102 +++++++++++++++++ .../qpid/client/perf/MessageConsumerTest.java | 74 ++++++------ .../java/org/apache/qpid/client/perf/Options.java | 4 +- 5 files changed, 262 insertions(+), 133 deletions(-) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSSyncConsumer.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java new file mode 100644 index 0000000000..111b43dfb9 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java @@ -0,0 +1,91 @@ +/* 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.qpid.client.perf; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.*; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * + * + */ +public class JMSAsyncConsumer implements MessageListener, JMSConsumer +{ + private static final Logger _logger = LoggerFactory.getLogger(JMSSyncConsumer.class); + + private String _id; + private Connection _connection; + private Session _session; + private MessageConsumer _consumer; + private Destination _destination; + private boolean _transacted; + private int _ackMode = Session.AUTO_ACKNOWLEDGE; + private AtomicBoolean _run = new AtomicBoolean(true); + private long _currentMsgCount; + + /* Not implementing transactions for first phase */ + public JMSAsyncConsumer(String id,Connection connection, Destination destination,boolean transacted,int ackMode) throws Exception + { + _id = id; + _connection = connection; + _destination = destination; + _transacted = transacted; + _ackMode = ackMode; + _session = _connection.createSession(_transacted, _ackMode); + _consumer = _session.createConsumer(_destination); + _consumer.setMessageListener(this); + } + + + + public void onMessage(Message message) + { + _currentMsgCount ++; + } + + public void stopConsuming() + { + System.out.println("Producer received notification to stop"); + try + { + _session.close(); + _connection.close(); + } + catch(Exception e) + { + _logger.error("Error Closing JMSSyncConsumer:"+ _id, e); + } + } + + public String getId() + { + return _id; + } + + /* Not worried about synchronizing as accuracy here is not that important. + * So if this method is invoked the count maybe off by a few digits. + * But when the test stops, this will always return the proper count. + */ + public long getCurrentMessageCount() + { + return _currentMsgCount; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java index 635fcaa248..4c41461cd4 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java @@ -1,102 +1,30 @@ +/* + * 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.qpid.client.perf; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.jms.BytesMessage; -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.MessageConsumer; -import javax.jms.Session; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class JMSConsumer implements Runnable +/** + * + * + */ +public interface JMSConsumer { - private static final Logger _logger = LoggerFactory.getLogger(JMSConsumer.class); - - private String _id; - private Connection _connection; - private Session _session; - private MessageConsumer _consumer; - private Destination _destination; - private boolean _transacted; - private int _ackMode = Session.AUTO_ACKNOWLEDGE; - private AtomicBoolean _run = new AtomicBoolean(true); - private long _currentMsgCount; - - /* Not implementing transactions for first phase */ - public JMSConsumer(String id,Connection connection, Destination destination,boolean transacted,int ackMode) throws Exception - { - _id = id; - _connection = connection; - _destination = destination; - _transacted = transacted; - _ackMode = ackMode; - } - - public void run() - { - _run.set(true); - - try - { - _session = _connection.createSession(_transacted, _ackMode); - _consumer = _session.createConsumer(_destination); - } - catch(Exception e) - { - _logger.error("Error Setting up JMSProducer:"+ _id, e); - } - - while (_run.get()) - { - try - { - BytesMessage msg = (BytesMessage)_consumer.receive(); - if (msg != null) - { - long msgId = Integer.parseInt(msg.getJMSCorrelationID()); - /*if (_currentMsgCount+1 != msgId) - { - _logger.error("Error : Message received out of order in JMSConsumer:" + _id + " message id was " + msgId + " expected: " + _currentMsgCount+1); - }*/ - _currentMsgCount ++; - } - } - catch(Exception e) - { - _logger.error("Error Receiving message from JMSConsumer:" + _id, e); - } - } - try - { - _session.close(); - _connection.close(); - } - catch(Exception e) - { - _logger.error("Error Closing JMSConsumer:"+ _id, e); - } - } - - public void stopConsuming() - { - _run.set(false); - System.out.println("Producer received notification to stop"); - } - - public String getId() - { - return _id; - } - - /* Not worried about synchronizing as accuracy here is not that important. - * So if this method is invoked the count maybe off by a few digits. - * But when the test stops, this will always return the proper count. - */ - public long getCurrentMessageCount() - { - return _currentMsgCount; - } + public String getId(); + public void stopConsuming(); + public long getCurrentMessageCount(); } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSSyncConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSSyncConsumer.java new file mode 100644 index 0000000000..5fd103746b --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSSyncConsumer.java @@ -0,0 +1,102 @@ +package org.apache.qpid.client.perf; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JMSSyncConsumer implements Runnable, JMSConsumer +{ + private static final Logger _logger = LoggerFactory.getLogger(JMSSyncConsumer.class); + + private String _id; + private Connection _connection; + private Session _session; + private MessageConsumer _consumer; + private Destination _destination; + private boolean _transacted; + private int _ackMode = Session.AUTO_ACKNOWLEDGE; + private AtomicBoolean _run = new AtomicBoolean(true); + private long _currentMsgCount; + + /* Not implementing transactions for first phase */ + public JMSSyncConsumer(String id,Connection connection, Destination destination,boolean transacted,int ackMode) throws Exception + { + _id = id; + _connection = connection; + _destination = destination; + _transacted = transacted; + _ackMode = ackMode; + } + + public void run() + { + _run.set(true); + + try + { + _session = _connection.createSession(_transacted, _ackMode); + _consumer = _session.createConsumer(_destination); + } + catch(Exception e) + { + _logger.error("Error Setting up JMSProducer:"+ _id, e); + } + + while (_run.get()) + { + try + { + BytesMessage msg = (BytesMessage)_consumer.receive(); + if (msg != null) + { + // long msgId = Integer.parseInt(msg.getJMSCorrelationID()); + /*if (_currentMsgCount+1 != msgId) + { + _logger.error("Error : Message received out of order in JMSSyncConsumer:" + _id + " message id was " + msgId + " expected: " + _currentMsgCount+1); + }*/ + _currentMsgCount ++; + } + } + catch(Exception e) + { + _logger.error("Error Receiving message from JMSSyncConsumer:" + _id, e); + } + } + try + { + _session.close(); + _connection.close(); + } + catch(Exception e) + { + _logger.error("Error Closing JMSSyncConsumer:"+ _id, e); + } + } + + public void stopConsuming() + { + _run.set(false); + System.out.println("Producer received notification to stop"); + } + + public String getId() + { + return _id; + } + + /* Not worried about synchronizing as accuracy here is not that important. + * So if this method is invoked the count maybe off by a few digits. + * But when the test stops, this will always return the proper count. + */ + public long getCurrentMessageCount() + { + return _currentMsgCount; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java index 99659fed44..52356ae243 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java @@ -1,13 +1,11 @@ package org.apache.qpid.client.perf; import java.io.FileWriter; -import java.io.RandomAccessFile; import java.sql.Date; import java.text.SimpleDateFormat; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import javax.jms.Connection; import javax.jms.Destination; import javax.jms.Session; @@ -21,7 +19,7 @@ public class MessageConsumerTest extends Options implements Runnable private static final Logger _logger = LoggerFactory.getLogger(MessageConsumerTest.class); private SimpleDateFormat df = new SimpleDateFormat("h:mm a"); - private Map _consumers = new ConcurrentHashMap(); + private Map _consumers = new ConcurrentHashMap(); private int _count; String _logFileName; private long _gracePeriod = 5 * 60 * 1000; @@ -30,30 +28,38 @@ public class MessageConsumerTest extends Options implements Runnable public void start() throws Exception { - this.parseOptions(); - boolean useSameDest = true; - _logFileName = _logFilePath + "/MessageConsumerTest_" + System.currentTimeMillis(); + this.parseOptions(); + boolean useSameDest = true; + _logFileName = _logFilePath + "/MessageConsumerTest_" + System.currentTimeMillis(); - // use each destination with a different producer - if (_producerCount == destArray.length) - { - useSameDest = false; - } - for (;_count < _producerCount;_count++) - { - createAndStartProducer(useSameDest?destArray[0]:destArray[_count]); - } + // use each destination with a different producer + if (_producerCount == destArray.length) + { + useSameDest = false; + } + for (; _count < _producerCount; _count++) + { + createAndStartConsumer(useSameDest ? destArray[0] : destArray[_count]); + } } - private void createAndStartProducer(String routingKey)throws Exception + private void createAndStartConsumer(String routingKey) throws Exception { AMQConnection con = ConnectionUtility.getInstance().getConnection(); con.start(); - Destination dest = new AMQTopic(con,routingKey); - JMSConsumer prod = new JMSConsumer(String.valueOf(_count),(Connection)con, dest, _transacted,Session.AUTO_ACKNOWLEDGE); - Thread t = new Thread(prod); - t.setName("JMSConsumer-"+_count); - t.start(); + Destination dest = new AMQTopic(con, routingKey); + JMSConsumer prod; + if (_synchronous) + { + prod = new JMSSyncConsumer(String.valueOf(_count), con, dest, _transacted, Session.AUTO_ACKNOWLEDGE); + Thread t = new Thread((JMSSyncConsumer) prod); + t.setName("JMSSyncConsumer-" + _count); + t.start(); + } + else + { + prod = new JMSAsyncConsumer(String.valueOf(_count), con, dest, _transacted, Session.AUTO_ACKNOWLEDGE); + } _consumers.put(_count, prod); } @@ -71,12 +77,12 @@ public class MessageConsumerTest extends Options implements Runnable runReaper(false); try { - while(run) + while (run) { Thread.sleep(_logDuration); runReaper(false); - if(System.currentTimeMillis() + _gracePeriod - _startTime > _expiry ) + if (System.currentTimeMillis() + _gracePeriod - _startTime > _expiry) { // time to stop the test. for (Integer id : _consumers.keySet()) @@ -91,7 +97,7 @@ public class MessageConsumerTest extends Options implements Runnable } catch (InterruptedException e) { - _logger.error("The timer thread exited",e); + _logger.error("The timer thread exited", e); } } @@ -99,11 +105,11 @@ public class MessageConsumerTest extends Options implements Runnable { try { - FileWriter _logFile = new FileWriter(_logFileName + ".csv",true); + FileWriter _logFile = new FileWriter(_logFileName + ".csv", true); for (Integer id : _consumers.keySet()) { JMSConsumer prod = _consumers.get(id); - StringBuffer buf = new StringBuffer("JMSConsumer(").append(prod.getId()).append("),"); + StringBuffer buf = new StringBuffer("JMSSyncConsumer(").append(prod.getId()).append("),"); Date d = new Date(System.currentTimeMillis()); buf.append(df.format(d)).append(","); buf.append(d.getTime()).append(","); @@ -113,21 +119,21 @@ public class MessageConsumerTest extends Options implements Runnable } _logFile.close(); - FileWriter _memoryLog = new FileWriter(_logFileName + "_memory.csv",true); - StringBuffer buf = new StringBuffer("JMSConsumer,"); + FileWriter _memoryLog = new FileWriter(_logFileName + "_memory.csv", true); + StringBuffer buf = new StringBuffer("JMSSyncConsumer,"); Date d = new Date(System.currentTimeMillis()); buf.append(df.format(d)).append(","); buf.append(d.getTime()).append(","); buf.append(totalMsgCount).append(","); - buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); + buf.append(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()).append("\n"); _memoryLog.write(buf.toString()); _memoryLog.close(); if (printSummary) { double totaltime = d.getTime() - _startTime; double dCount = totalMsgCount; - double ratio = (dCount/totaltime)*1000; - FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); + double ratio = (dCount / totaltime) * 1000; + FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary", true); buf = new StringBuffer("MessageConsumerTest \n Test started at : "); buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); d = new Date(System.currentTimeMillis()); @@ -140,9 +146,9 @@ public class MessageConsumerTest extends Options implements Runnable _summaryLog.close(); } } - catch(Exception e) + catch (Exception e) { - _logger.error("Error printing info to the log file",e); + _logger.error("Error printing info to the log file", e); } } @@ -154,7 +160,7 @@ public class MessageConsumerTest extends Options implements Runnable test.start(); test.startTimerThread(); } - catch(Exception e) + catch (Exception e) { e.printStackTrace(); } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java index ee22b6804b..0ff420bf75 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java @@ -4,6 +4,7 @@ public class Options { int _messageSize; boolean _transacted; + boolean _synchronous; String[] destArray; int _producerCount; int _consumerCount; @@ -25,6 +26,7 @@ public class Options public void parseOptions() { _messageSize = Integer.parseInt(System.getProperty("messageSize","100")); + _synchronous =Boolean.parseBoolean( System.getProperty("synchronous", "false")); _transacted = false; String destinations = System.getProperty("destinations"); destArray = destinations.split(","); @@ -37,7 +39,7 @@ public class Options System.out.println("============= Test Data ==================="); System.out.println("Total no of producers : " + _producerCount); - System.out.println("Total no of consumer : " + _consumerCount); + System.out.println(_synchronous? "Total no of synchronous consumers : " : "Total no of asynchronous consumers :" + _consumerCount); System.out.println("Log Frequency in mins : " + _logDuration/(1000*60)); System.out.println("Log file path : " + _logFilePath); System.out.println("Test Duration : " + printTestDuration()); -- cgit v1.2.1 From bbe8a15519d991af717a3bff50d10ea102131fca Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Tue, 20 Nov 2007 22:25:12 +0000 Subject: Added a jvm option verify message order git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@596850 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/client/perf/JMSAsyncConsumer.java | 22 ++++++++++++++++++---- .../apache/qpid/client/perf/JMSSyncConsumer.java | 2 +- .../java/org/apache/qpid/client/perf/Options.java | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java index 111b43dfb9..f0d10ec144 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java @@ -5,9 +5,9 @@ * 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 @@ -40,6 +40,7 @@ public class JMSAsyncConsumer implements MessageListener, JMSConsumer private int _ackMode = Session.AUTO_ACKNOWLEDGE; private AtomicBoolean _run = new AtomicBoolean(true); private long _currentMsgCount; + private boolean _verifyOrder = false; /* Not implementing transactions for first phase */ public JMSAsyncConsumer(String id,Connection connection, Destination destination,boolean transacted,int ackMode) throws Exception @@ -52,18 +53,31 @@ public class JMSAsyncConsumer implements MessageListener, JMSConsumer _session = _connection.createSession(_transacted, _ackMode); _consumer = _session.createConsumer(_destination); _consumer.setMessageListener(this); + _verifyOrder = Boolean.getBoolean("verifyOrder"); } public void onMessage(Message message) { - _currentMsgCount ++; + try + { + long msgId = Integer.parseInt(message.getJMSCorrelationID()); + if (_verifyOrder && _currentMsgCount+1 != msgId) + { + _logger.error("Error : Message received out of order in JMSSyncConsumer:" + _id + " message id was " + msgId + " expected: " + _currentMsgCount+1); + } + _currentMsgCount ++; + } + catch(Exception e) + { + e.printStackTrace(); + } } public void stopConsuming() { - System.out.println("Producer received notification to stop"); + System.out.println("Consumer received notification to stop"); try { _session.close(); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSSyncConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSSyncConsumer.java index 5fd103746b..b320f3cdfc 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSSyncConsumer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSSyncConsumer.java @@ -83,7 +83,7 @@ public class JMSSyncConsumer implements Runnable, JMSConsumer public void stopConsuming() { _run.set(false); - System.out.println("Producer received notification to stop"); + System.out.println("Consumer received notification to stop"); } public String getId() diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java index 0ff420bf75..7fddbbeeb7 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java @@ -26,7 +26,7 @@ public class Options public void parseOptions() { _messageSize = Integer.parseInt(System.getProperty("messageSize","100")); - _synchronous =Boolean.parseBoolean( System.getProperty("synchronous", "false")); + _synchronous = Boolean.parseBoolean( System.getProperty("synchronous", "false")); _transacted = false; String destinations = System.getProperty("destinations"); destArray = destinations.split(","); -- cgit v1.2.1 From 70316b32a0cffd26a4ee4fb763a598bba9546d1e Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Thu, 22 Nov 2007 19:04:37 +0000 Subject: Added prod.setDisableMessageTimestamp(true); git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@597477 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/client/perf/JMSProducer.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java index 60913795ba..58b17efecc 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java @@ -45,6 +45,8 @@ public class JMSProducer implements Runnable _session = _connection.createSession(_transacted, _ackMode); _payload = TestMessageFactory.newBytesMessage(_session, _messageSize); _producer = _session.createProducer(_destination); + // this should speedup the message producer + _producer.setDisableMessageTimestamp(true); } catch(Exception e) { -- cgit v1.2.1 From ec2e89d1807d6dad9d678e2043c5f0e8c85d07c8 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Wed, 28 Nov 2007 19:47:26 +0000 Subject: Added the -DuseQueue option to switch between pub/sub and p2p. If useQueue is present then we use p2p. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@599117 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java | 3 ++- .../src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java | 3 ++- .../perftests/src/main/java/org/apache/qpid/client/perf/Options.java | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java index 52356ae243..116fb79246 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java @@ -10,6 +10,7 @@ import javax.jms.Destination; import javax.jms.Session; import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,7 +48,7 @@ public class MessageConsumerTest extends Options implements Runnable { AMQConnection con = ConnectionUtility.getInstance().getConnection(); con.start(); - Destination dest = new AMQTopic(con, routingKey); + Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(con,routingKey) : new AMQTopic(con,routingKey); JMSConsumer prod; if (_synchronous) { diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java index b0ea28292d..1710c5ca09 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java @@ -10,6 +10,7 @@ import javax.jms.Connection; import javax.jms.Destination; import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,7 +47,7 @@ public class MessageProducerTest extends Options implements Runnable { AMQConnection con = ConnectionUtility.getInstance().getConnection(); con.start(); - Destination dest = new AMQTopic(con,routingKey); + Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(con,routingKey) : new AMQTopic(con,routingKey); JMSProducer prod = new JMSProducer(String.valueOf(_count),(Connection)con, dest,_messageSize, _transacted); Thread t = new Thread(prod); t.setName("JMSProducer-"+_count); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java index 7fddbbeeb7..2d04426794 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java @@ -15,6 +15,7 @@ public class Options /** * System props * -DmessageSize + * -DuseQueue * -Dtransacted * -DproducerCount * -DconsumerCount -- cgit v1.2.1 From aa2fde9d1f555488db5182631d8f7d80adc8d2cf Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Thu, 29 Nov 2007 03:54:53 +0000 Subject: Setting the message to null to mark for garbage collection noAck still has to clear our internal command ids. increased the default max prefetch to 1000 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@599255 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java | 1 + 1 file changed, 1 insertion(+) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java index f0d10ec144..3f21a3f0a6 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java @@ -67,6 +67,7 @@ public class JMSAsyncConsumer implements MessageListener, JMSConsumer { _logger.error("Error : Message received out of order in JMSSyncConsumer:" + _id + " message id was " + msgId + " expected: " + _currentMsgCount+1); } + message = null; _currentMsgCount ++; } catch(Exception e) -- cgit v1.2.1 From 8d96d7c588af524ec10052a966c2ec5707f8bac0 Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Thu, 29 Nov 2007 12:12:08 +0000 Subject: added interval thoughput calculation git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@599403 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/perf/MessageProducerTest.java | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java index 1710c5ca09..ef91e27604 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java @@ -24,7 +24,8 @@ public class MessageProducerTest extends Options implements Runnable private int _count; String _logFileName; long _startTime; - long totalMsgCount; + long _totalMsgCount; + double _timeElapsed = 0; public void start() throws Exception { @@ -98,6 +99,8 @@ public class MessageProducerTest extends Options implements Runnable try { FileWriter _logFile = new FileWriter(_logFileName + ".csv",true); + long newTotalMsgCount = 0; + long totalMsgCountThisInterval = 0; for (Integer id : _producers.keySet()) { JMSProducer prod = _producers.get(id); @@ -107,23 +110,29 @@ public class MessageProducerTest extends Options implements Runnable buf.append(d.getTime()).append(","); buf.append(prod.getCurrentMessageCount()).append("\n"); _logFile.write(buf.toString()); - totalMsgCount = totalMsgCount + prod.getCurrentMessageCount(); + newTotalMsgCount = newTotalMsgCount + prod.getCurrentMessageCount(); + totalMsgCountThisInterval = newTotalMsgCount - _totalMsgCount; + _totalMsgCount = newTotalMsgCount; } _logFile.close(); FileWriter _memoryLog = new FileWriter(_logFileName + "_memory.csv",true); StringBuffer buf = new StringBuffer("JMSProducer,"); Date d = new Date(System.currentTimeMillis()); + double totaltime = d.getTime() - _startTime; + _timeElapsed = totaltime - _timeElapsed; buf.append(df.format(d)).append(","); buf.append(d.getTime()).append(","); - buf.append(totalMsgCount).append(","); + buf.append(_totalMsgCount).append(","); buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); + buf.append("\n"); + buf.append("Throughput: total " + (_totalMsgCount /totaltime)*1000 + " msg/s; this interval: " + (totalMsgCountThisInterval/_timeElapsed)*1000 + " msg/s"); _memoryLog.write(buf.toString()); _memoryLog.close(); + System.out.println(buf); if (printSummary) { - double totaltime = d.getTime() - _startTime; - double dCount = totalMsgCount; + double dCount = _totalMsgCount; double ratio = (dCount/totaltime)*1000; FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); buf = new StringBuffer("MessageProducerTest \n Test started at : "); @@ -131,12 +140,13 @@ public class MessageProducerTest extends Options implements Runnable d = new Date(System.currentTimeMillis()); buf.append(df.format(d)).append("\n Total Time taken (ms):"); buf.append(totaltime).append("\n Total messages sent:"); - buf.append(totalMsgCount).append("\n Producer rate:"); + buf.append(_totalMsgCount).append("\n Producer rate:"); buf.append(ratio).append("\n"); _summaryLog.write(buf.toString()); System.out.println("---------- Test Ended -------------"); _summaryLog.close(); } + _timeElapsed = totaltime; } catch(Exception e) { -- cgit v1.2.1 From e38196b7d9cfa003a18abb59cdaa5e838c927576 Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Thu, 29 Nov 2007 12:53:54 +0000 Subject: added interval thoughput calculation git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@599424 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/perf/MessageConsumerTest.java | 36 ++++++++++++++-------- 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java index 116fb79246..8fa3b51527 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java @@ -26,6 +26,8 @@ public class MessageConsumerTest extends Options implements Runnable private long _gracePeriod = 5 * 60 * 1000; long _startTime; long totalMsgCount; + long _totalMsgCount; + double _timeElapsed = 0; public void start() throws Exception { @@ -107,6 +109,9 @@ public class MessageConsumerTest extends Options implements Runnable try { FileWriter _logFile = new FileWriter(_logFileName + ".csv", true); + long newTotalMsgCount = 0; + long totalMsgCountThisInterval = 0; + for (Integer id : _consumers.keySet()) { JMSConsumer prod = _consumers.get(id); @@ -116,36 +121,43 @@ public class MessageConsumerTest extends Options implements Runnable buf.append(d.getTime()).append(","); buf.append(prod.getCurrentMessageCount()).append("\n"); _logFile.write(buf.toString()); - totalMsgCount = totalMsgCount + prod.getCurrentMessageCount(); + newTotalMsgCount = newTotalMsgCount + prod.getCurrentMessageCount(); + totalMsgCountThisInterval = newTotalMsgCount - _totalMsgCount; + _totalMsgCount = newTotalMsgCount; } _logFile.close(); - FileWriter _memoryLog = new FileWriter(_logFileName + "_memory.csv", true); - StringBuffer buf = new StringBuffer("JMSSyncConsumer,"); + FileWriter _memoryLog = new FileWriter(_logFileName + "_memory.csv",true); + StringBuffer buf = new StringBuffer("JMSProducer,"); Date d = new Date(System.currentTimeMillis()); + double totaltime = d.getTime() - _startTime; + _timeElapsed = totaltime - _timeElapsed; buf.append(df.format(d)).append(","); buf.append(d.getTime()).append(","); - buf.append(totalMsgCount).append(","); - buf.append(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()).append("\n"); + buf.append(_totalMsgCount).append(","); + buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); + buf.append("\n"); + buf.append("Throughput: total " + (_totalMsgCount /totaltime)*1000 + " msg/s; this interval: " + (totalMsgCountThisInterval/_timeElapsed)*1000 + " msg/s"); _memoryLog.write(buf.toString()); _memoryLog.close(); + System.out.println(buf); if (printSummary) { - double totaltime = d.getTime() - _startTime; - double dCount = totalMsgCount; - double ratio = (dCount / totaltime) * 1000; - FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary", true); - buf = new StringBuffer("MessageConsumerTest \n Test started at : "); + double dCount = _totalMsgCount; + double ratio = (dCount/totaltime)*1000; + FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); + buf = new StringBuffer("MessageProducerTest \n Test started at : "); buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); d = new Date(System.currentTimeMillis()); buf.append(df.format(d)).append("\n Total Time taken (ms):"); - buf.append(totaltime).append("\n Total messages received:"); - buf.append(totalMsgCount).append("\n Consumer rate:"); + buf.append(totaltime).append("\n Total messages sent:"); + buf.append(_totalMsgCount).append("\n Producer rate:"); buf.append(ratio).append("\n"); _summaryLog.write(buf.toString()); System.out.println("---------- Test Ended -------------"); _summaryLog.close(); } + _timeElapsed = totaltime; } catch (Exception e) { -- cgit v1.2.1 From ba07a398f938270d10a28a36437ff5b06c5fca53 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Thu, 29 Nov 2007 17:47:41 +0000 Subject: Cleaned up the calculations and added an option to disable interval stat collection git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@599528 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/perf/MessageConsumerTest.java | 134 +++++++++++++-------- .../qpid/client/perf/MessageProducerTest.java | 132 ++++++++++++-------- 2 files changed, 164 insertions(+), 102 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java index 8fa3b51527..831d4dd9c4 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java @@ -1,6 +1,7 @@ package org.apache.qpid.client.perf; import java.io.FileWriter; +import java.io.IOException; import java.sql.Date; import java.text.SimpleDateFormat; import java.util.Map; @@ -25,9 +26,7 @@ public class MessageConsumerTest extends Options implements Runnable String _logFileName; private long _gracePeriod = 5 * 60 * 1000; long _startTime; - long totalMsgCount; long _totalMsgCount; - double _timeElapsed = 0; public void start() throws Exception { @@ -35,12 +34,12 @@ public class MessageConsumerTest extends Options implements Runnable boolean useSameDest = true; _logFileName = _logFilePath + "/MessageConsumerTest_" + System.currentTimeMillis(); - // use each destination with a different producer - if (_producerCount == destArray.length) + // use each destination with a different consumerucer + if (_consumerCount == destArray.length) { useSameDest = false; } - for (; _count < _producerCount; _count++) + for (; _count < _consumerCount; _count++) { createAndStartConsumer(useSameDest ? destArray[0] : destArray[_count]); } @@ -51,39 +50,51 @@ public class MessageConsumerTest extends Options implements Runnable AMQConnection con = ConnectionUtility.getInstance().getConnection(); con.start(); Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(con,routingKey) : new AMQTopic(con,routingKey); - JMSConsumer prod; + JMSConsumer consumer; if (_synchronous) { - prod = new JMSSyncConsumer(String.valueOf(_count), con, dest, _transacted, Session.AUTO_ACKNOWLEDGE); - Thread t = new Thread((JMSSyncConsumer) prod); + consumer = new JMSSyncConsumer(String.valueOf(_count), con, dest, _transacted, Session.AUTO_ACKNOWLEDGE); + Thread t = new Thread((JMSSyncConsumer) consumer); t.setName("JMSSyncConsumer-" + _count); t.start(); } else { - prod = new JMSAsyncConsumer(String.valueOf(_count), con, dest, _transacted, Session.AUTO_ACKNOWLEDGE); + consumer = new JMSAsyncConsumer(String.valueOf(_count), con, dest, _transacted, Session.AUTO_ACKNOWLEDGE); } - _consumers.put(_count, prod); + _consumers.put(_count, consumer); } private void startTimerThread() { - Thread t = new Thread(this); - t.setName("MessageConsumerTest-TimerThread"); - t.start(); + _startTime = System.currentTimeMillis(); + if(Boolean.getBoolean("collect_stats")) + { + Thread t = new Thread(this); + t.setName("MessageConsumerTest-TimerThread"); + t.start(); + } + try + { + printSummary(); + } + catch(Exception e) + { + e.printStackTrace(); + } } public void run() { boolean run = true; - _startTime = System.currentTimeMillis(); - runReaper(false); + printHeading(); + runReaper(); try { while (run) { Thread.sleep(_logDuration); - runReaper(false); + runReaper(); if (System.currentTimeMillis() + _gracePeriod - _startTime > _expiry) { @@ -93,7 +104,7 @@ public class MessageConsumerTest extends Options implements Runnable JMSConsumer consumer = _consumers.get(id); consumer.stopConsuming(); } - runReaper(true); + runReaper(); run = false; } } @@ -104,60 +115,35 @@ public class MessageConsumerTest extends Options implements Runnable } } - public void runReaper(boolean printSummary) + public void runReaper() { try { - FileWriter _logFile = new FileWriter(_logFileName + ".csv", true); - long newTotalMsgCount = 0; long totalMsgCountThisInterval = 0; for (Integer id : _consumers.keySet()) { - JMSConsumer prod = _consumers.get(id); - StringBuffer buf = new StringBuffer("JMSSyncConsumer(").append(prod.getId()).append("),"); - Date d = new Date(System.currentTimeMillis()); - buf.append(df.format(d)).append(","); - buf.append(d.getTime()).append(","); - buf.append(prod.getCurrentMessageCount()).append("\n"); - _logFile.write(buf.toString()); - newTotalMsgCount = newTotalMsgCount + prod.getCurrentMessageCount(); - totalMsgCountThisInterval = newTotalMsgCount - _totalMsgCount; - _totalMsgCount = newTotalMsgCount; + JMSConsumer consumer = _consumers.get(id); + totalMsgCountThisInterval = totalMsgCountThisInterval + consumer.getCurrentMessageCount(); + } - _logFile.close(); + _totalMsgCount = _totalMsgCount + totalMsgCountThisInterval; - FileWriter _memoryLog = new FileWriter(_logFileName + "_memory.csv",true); - StringBuffer buf = new StringBuffer("JMSProducer,"); + FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); + StringBuffer buf = new StringBuffer(); Date d = new Date(System.currentTimeMillis()); double totaltime = d.getTime() - _startTime; - _timeElapsed = totaltime - _timeElapsed; buf.append(df.format(d)).append(","); buf.append(d.getTime()).append(","); buf.append(_totalMsgCount).append(","); + buf.append(_totalMsgCount*1000 /totaltime).append(","); + buf.append(totalMsgCountThisInterval).append(","); + buf.append(totalMsgCountThisInterval*1000/_logDuration).append(","); buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); buf.append("\n"); - buf.append("Throughput: total " + (_totalMsgCount /totaltime)*1000 + " msg/s; this interval: " + (totalMsgCountThisInterval/_timeElapsed)*1000 + " msg/s"); _memoryLog.write(buf.toString()); _memoryLog.close(); System.out.println(buf); - if (printSummary) - { - double dCount = _totalMsgCount; - double ratio = (dCount/totaltime)*1000; - FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); - buf = new StringBuffer("MessageProducerTest \n Test started at : "); - buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); - d = new Date(System.currentTimeMillis()); - buf.append(df.format(d)).append("\n Total Time taken (ms):"); - buf.append(totaltime).append("\n Total messages sent:"); - buf.append(_totalMsgCount).append("\n Producer rate:"); - buf.append(ratio).append("\n"); - _summaryLog.write(buf.toString()); - System.out.println("---------- Test Ended -------------"); - _summaryLog.close(); - } - _timeElapsed = totaltime; } catch (Exception e) { @@ -165,6 +151,50 @@ public class MessageConsumerTest extends Options implements Runnable } } + private void printHeading() + { + try + { + FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); + String s = "Date/Time,Time (ms),total msg count,total rate (msg/sec),interval count,interval rate (msg/sec),memory"; + _memoryLog.write(s); + _memoryLog.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + private void printSummary() throws Exception + { + if (Boolean.getBoolean("collect_stats")) + { + for (Integer id : _consumers.keySet()) + { + JMSConsumer consumer = _consumers.get(id); + _totalMsgCount = _totalMsgCount + consumer.getCurrentMessageCount(); + + } + } + + long current = System.currentTimeMillis(); + double time = current - _startTime; + double ratio = _totalMsgCount*1000/time; + FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); + + StringBuffer buf = new StringBuffer("MessageConsumerTest \n Test started at : "); + buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); + Date d = new Date(current); + buf.append(df.format(d)).append("\n Total Time taken (ms):"); + buf.append(time).append("\n Total messages sent:"); + buf.append(_totalMsgCount).append("\n consumer rate:"); + buf.append(ratio).append("\n"); + _summaryLog.write(buf.toString()); + System.out.println("---------- Test Ended -------------"); + _summaryLog.close(); + } + public static void main(String[] args) { try diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java index ef91e27604..67a3aaa786 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java @@ -1,6 +1,7 @@ package org.apache.qpid.client.perf; import java.io.FileWriter; +import java.io.IOException; import java.sql.Date; import java.text.SimpleDateFormat; import java.util.Map; @@ -25,7 +26,6 @@ public class MessageProducerTest extends Options implements Runnable String _logFileName; long _startTime; long _totalMsgCount; - double _timeElapsed = 0; public void start() throws Exception { @@ -58,102 +58,134 @@ public class MessageProducerTest extends Options implements Runnable private void startTimerThread() { - Thread t = new Thread(this); - t.setName("MessageProducerTest-TimerThread"); - t.start(); + _startTime = System.currentTimeMillis(); + if(Boolean.getBoolean("collect_stats")) + { + Thread t = new Thread(this); + t.setName("MessageProducerTest-TimerThread"); + t.start(); + } + try + { + printSummary(); + } + catch(Exception e) + { + e.printStackTrace(); + } } public void run() { boolean run = true; - _startTime = System.currentTimeMillis(); - runReaper(false); + printHeading(); + runReaper(); try { - while(run) + while (run) { Thread.sleep(_logDuration); - runReaper(false); + runReaper(); - if(System.currentTimeMillis() - _startTime > _expiry ) + if (System.currentTimeMillis() - _startTime > _expiry) { // time to stop the test. for (Integer id : _producers.keySet()) { - JMSProducer prod = _producers.get(id); - prod.stopProducing(); + JMSProducer producer = _producers.get(id); + producer.stopProducing(); } - runReaper(true); + runReaper(); run = false; } } } catch (InterruptedException e) { - _logger.error("The timer thread exited",e); + _logger.error("The timer thread exited", e); } } - public void runReaper(boolean printSummary) + public void runReaper() { try { - FileWriter _logFile = new FileWriter(_logFileName + ".csv",true); - long newTotalMsgCount = 0; long totalMsgCountThisInterval = 0; + for (Integer id : _producers.keySet()) { - JMSProducer prod = _producers.get(id); - StringBuffer buf = new StringBuffer("JMSProducer(").append(prod.getId()).append("),"); - Date d = new Date(System.currentTimeMillis()); - buf.append(df.format(d)).append(","); - buf.append(d.getTime()).append(","); - buf.append(prod.getCurrentMessageCount()).append("\n"); - _logFile.write(buf.toString()); - newTotalMsgCount = newTotalMsgCount + prod.getCurrentMessageCount(); - totalMsgCountThisInterval = newTotalMsgCount - _totalMsgCount; - _totalMsgCount = newTotalMsgCount; + JMSProducer producer = _producers.get(id); + totalMsgCountThisInterval = totalMsgCountThisInterval + producer.getCurrentMessageCount(); + } - _logFile.close(); + _totalMsgCount = _totalMsgCount + totalMsgCountThisInterval; - FileWriter _memoryLog = new FileWriter(_logFileName + "_memory.csv",true); - StringBuffer buf = new StringBuffer("JMSProducer,"); + FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); + StringBuffer buf = new StringBuffer(); Date d = new Date(System.currentTimeMillis()); double totaltime = d.getTime() - _startTime; - _timeElapsed = totaltime - _timeElapsed; buf.append(df.format(d)).append(","); buf.append(d.getTime()).append(","); buf.append(_totalMsgCount).append(","); + buf.append(_totalMsgCount*1000 /totaltime).append(","); + buf.append(totalMsgCountThisInterval).append(","); + buf.append(totalMsgCountThisInterval*1000/_logDuration).append(","); buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); buf.append("\n"); - buf.append("Throughput: total " + (_totalMsgCount /totaltime)*1000 + " msg/s; this interval: " + (totalMsgCountThisInterval/_timeElapsed)*1000 + " msg/s"); _memoryLog.write(buf.toString()); _memoryLog.close(); System.out.println(buf); - if (printSummary) - { - double dCount = _totalMsgCount; - double ratio = (dCount/totaltime)*1000; - FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); - buf = new StringBuffer("MessageProducerTest \n Test started at : "); - buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); - d = new Date(System.currentTimeMillis()); - buf.append(df.format(d)).append("\n Total Time taken (ms):"); - buf.append(totaltime).append("\n Total messages sent:"); - buf.append(_totalMsgCount).append("\n Producer rate:"); - buf.append(ratio).append("\n"); - _summaryLog.write(buf.toString()); - System.out.println("---------- Test Ended -------------"); - _summaryLog.close(); - } - _timeElapsed = totaltime; } - catch(Exception e) + catch (Exception e) + { + _logger.error("Error printing info to the log file", e); + } + } + + private void printHeading() + { + try + { + FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); + String s = "Date/Time,Time (ms),total msg count,total rate (msg/sec),interval count,interval rate (msg/sec),memory"; + _memoryLog.write(s); + _memoryLog.close(); + } + catch (IOException e) { - _logger.error("Error printing info to the log file",e); + e.printStackTrace(); } } + private void printSummary() throws Exception + { + if (Boolean.getBoolean("collect_stats")) + { + for (Integer id : _producers.keySet()) + { + JMSProducer producer = _producers.get(id); + _totalMsgCount = _totalMsgCount + producer.getCurrentMessageCount(); + + } + } + + long current = System.currentTimeMillis(); + double time = current - _startTime; + double ratio = _totalMsgCount*1000/time; + FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); + + StringBuffer buf = new StringBuffer("MessageProducerTest \n Test started at : "); + buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); + Date d = new Date(current); + buf.append(df.format(d)).append("\n Total Time taken (ms):"); + buf.append(time).append("\n Total messages sent:"); + buf.append(_totalMsgCount).append("\n producer rate:"); + buf.append(ratio).append("\n"); + _summaryLog.write(buf.toString()); + System.out.println("---------- Test Ended -------------"); + _summaryLog.close(); + } + public static void main(String[] args) { try -- cgit v1.2.1 From 5ae1ec0df4a3d088e413d5d1e4c534409b307155 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Thu, 29 Nov 2007 22:46:28 +0000 Subject: Removed all the fancy threading with the test cases as these interfer with the test cases git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@599611 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/client/perf/JMSAsyncConsumer.java | 106 ----------- .../org/apache/qpid/client/perf/JMSConsumer.java | 30 ---- .../org/apache/qpid/client/perf/JMSProducer.java | 99 ----------- .../apache/qpid/client/perf/JMSSyncConsumer.java | 102 ----------- .../qpid/client/perf/MessageConsumerTest.java | 195 +++++++++------------ .../qpid/client/perf/MessageProducerTest.java | 158 +++++++---------- .../java/org/apache/qpid/client/perf/Options.java | 23 +-- 7 files changed, 154 insertions(+), 559 deletions(-) delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSSyncConsumer.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java deleted file mode 100644 index 3f21a3f0a6..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSAsyncConsumer.java +++ /dev/null @@ -1,106 +0,0 @@ -/* 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.qpid.client.perf; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.jms.*; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * - * - */ -public class JMSAsyncConsumer implements MessageListener, JMSConsumer -{ - private static final Logger _logger = LoggerFactory.getLogger(JMSSyncConsumer.class); - - private String _id; - private Connection _connection; - private Session _session; - private MessageConsumer _consumer; - private Destination _destination; - private boolean _transacted; - private int _ackMode = Session.AUTO_ACKNOWLEDGE; - private AtomicBoolean _run = new AtomicBoolean(true); - private long _currentMsgCount; - private boolean _verifyOrder = false; - - /* Not implementing transactions for first phase */ - public JMSAsyncConsumer(String id,Connection connection, Destination destination,boolean transacted,int ackMode) throws Exception - { - _id = id; - _connection = connection; - _destination = destination; - _transacted = transacted; - _ackMode = ackMode; - _session = _connection.createSession(_transacted, _ackMode); - _consumer = _session.createConsumer(_destination); - _consumer.setMessageListener(this); - _verifyOrder = Boolean.getBoolean("verifyOrder"); - } - - - - public void onMessage(Message message) - { - try - { - long msgId = Integer.parseInt(message.getJMSCorrelationID()); - if (_verifyOrder && _currentMsgCount+1 != msgId) - { - _logger.error("Error : Message received out of order in JMSSyncConsumer:" + _id + " message id was " + msgId + " expected: " + _currentMsgCount+1); - } - message = null; - _currentMsgCount ++; - } - catch(Exception e) - { - e.printStackTrace(); - } - } - - public void stopConsuming() - { - System.out.println("Consumer received notification to stop"); - try - { - _session.close(); - _connection.close(); - } - catch(Exception e) - { - _logger.error("Error Closing JMSSyncConsumer:"+ _id, e); - } - } - - public String getId() - { - return _id; - } - - /* Not worried about synchronizing as accuracy here is not that important. - * So if this method is invoked the count maybe off by a few digits. - * But when the test stops, this will always return the proper count. - */ - public long getCurrentMessageCount() - { - return _currentMsgCount; - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java deleted file mode 100644 index 4c41461cd4..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSConsumer.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.qpid.client.perf; - -/** - * - * - */ -public interface JMSConsumer -{ - public String getId(); - public void stopConsuming(); - public long getCurrentMessageCount(); -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java deleted file mode 100644 index 58b17efecc..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSProducer.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.apache.qpid.client.perf; - -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.jms.BytesMessage; -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.MessageProducer; -import javax.jms.Session; - -import org.apache.qpid.client.message.TestMessageFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class JMSProducer implements Runnable -{ - private static final Logger _logger = LoggerFactory.getLogger(JMSProducer.class); - - private String _id; - private int _messageSize; - private Connection _connection; - private Session _session; - private MessageProducer _producer; - private Destination _destination; - private BytesMessage _payload; - private boolean _transacted; - private int _ackMode = Session.AUTO_ACKNOWLEDGE; - private AtomicBoolean _run = new AtomicBoolean(true); - private long _currentMsgCount; - - /* Not implementing transactions for first phase */ - public JMSProducer(String id,Connection connection, Destination destination,int messageSize, boolean transacted) throws Exception - { - _id = id; - _connection = connection; - _destination = destination; - _messageSize = messageSize; - _transacted = transacted; - } - - public void run() - { - try - { - _session = _connection.createSession(_transacted, _ackMode); - _payload = TestMessageFactory.newBytesMessage(_session, _messageSize); - _producer = _session.createProducer(_destination); - // this should speedup the message producer - _producer.setDisableMessageTimestamp(true); - } - catch(Exception e) - { - _logger.error("Error Setting up JMSProducer:"+ _id, e); - } - - while (_run.get()) - { - try - { - _payload.setJMSCorrelationID(String.valueOf(_currentMsgCount+1)); - _producer.send(_payload); - _currentMsgCount ++; - } - catch(Exception e) - { - _logger.error("Error Sending message from JMSProducer:" + _id, e); - } - } - try - { - _session.close(); - _connection.close(); - } - catch(Exception e) - { - _logger.error("Error Closing JMSProducer:"+ _id, e); - } - } - - public void stopProducing() - { - _run.set(false); - System.out.println("Producer received notification to stop"); - } - - public String getId() - { - return _id; - } - - /* Not worried about synchronizing as accuracy here is not that important. - * So if this method is invoked the count maybe off by a few digits. - * But when the test stops, this will always return the proper count. - */ - public long getCurrentMessageCount() - { - return _currentMsgCount; - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSSyncConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSSyncConsumer.java deleted file mode 100644 index b320f3cdfc..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/JMSSyncConsumer.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.apache.qpid.client.perf; - -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.jms.BytesMessage; -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.MessageConsumer; -import javax.jms.Session; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class JMSSyncConsumer implements Runnable, JMSConsumer -{ - private static final Logger _logger = LoggerFactory.getLogger(JMSSyncConsumer.class); - - private String _id; - private Connection _connection; - private Session _session; - private MessageConsumer _consumer; - private Destination _destination; - private boolean _transacted; - private int _ackMode = Session.AUTO_ACKNOWLEDGE; - private AtomicBoolean _run = new AtomicBoolean(true); - private long _currentMsgCount; - - /* Not implementing transactions for first phase */ - public JMSSyncConsumer(String id,Connection connection, Destination destination,boolean transacted,int ackMode) throws Exception - { - _id = id; - _connection = connection; - _destination = destination; - _transacted = transacted; - _ackMode = ackMode; - } - - public void run() - { - _run.set(true); - - try - { - _session = _connection.createSession(_transacted, _ackMode); - _consumer = _session.createConsumer(_destination); - } - catch(Exception e) - { - _logger.error("Error Setting up JMSProducer:"+ _id, e); - } - - while (_run.get()) - { - try - { - BytesMessage msg = (BytesMessage)_consumer.receive(); - if (msg != null) - { - // long msgId = Integer.parseInt(msg.getJMSCorrelationID()); - /*if (_currentMsgCount+1 != msgId) - { - _logger.error("Error : Message received out of order in JMSSyncConsumer:" + _id + " message id was " + msgId + " expected: " + _currentMsgCount+1); - }*/ - _currentMsgCount ++; - } - } - catch(Exception e) - { - _logger.error("Error Receiving message from JMSSyncConsumer:" + _id, e); - } - } - try - { - _session.close(); - _connection.close(); - } - catch(Exception e) - { - _logger.error("Error Closing JMSSyncConsumer:"+ _id, e); - } - } - - public void stopConsuming() - { - _run.set(false); - System.out.println("Consumer received notification to stop"); - } - - public String getId() - { - return _id; - } - - /* Not worried about synchronizing as accuracy here is not that important. - * So if this method is invoked the count maybe off by a few digits. - * But when the test stops, this will always return the proper count. - */ - public long getCurrentMessageCount() - { - return _currentMsgCount; - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java index 831d4dd9c4..d820b22de9 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java @@ -4,114 +4,96 @@ import java.io.FileWriter; import java.io.IOException; import java.sql.Date; import java.text.SimpleDateFormat; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import javax.jms.BytesMessage; +import javax.jms.Connection; import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; import javax.jms.Session; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.message.TestMessageFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class MessageConsumerTest extends Options implements Runnable +public class MessageConsumerTest extends Options implements MessageListener { private static final Logger _logger = LoggerFactory.getLogger(MessageConsumerTest.class); private SimpleDateFormat df = new SimpleDateFormat("h:mm a"); - private Map _consumers = new ConcurrentHashMap(); - private int _count; String _logFileName; - private long _gracePeriod = 5 * 60 * 1000; long _startTime; long _totalMsgCount; + long _intervalCount; - public void start() throws Exception - { - this.parseOptions(); - boolean useSameDest = true; - _logFileName = _logFilePath + "/MessageConsumerTest_" + System.currentTimeMillis(); + private Connection _connection; + private Session _session; + private BytesMessage _payload; + private MessageConsumer _consumer; + private boolean _verifyOrder = false; - // use each destination with a different consumerucer - if (_consumerCount == destArray.length) - { - useSameDest = false; - } - for (; _count < _consumerCount; _count++) - { - createAndStartConsumer(useSameDest ? destArray[0] : destArray[_count]); - } - } - - private void createAndStartConsumer(String routingKey) throws Exception + public void init() throws Exception { - AMQConnection con = ConnectionUtility.getInstance().getConnection(); - con.start(); - Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(con,routingKey) : new AMQTopic(con,routingKey); - JMSConsumer consumer; - if (_synchronous) - { - consumer = new JMSSyncConsumer(String.valueOf(_count), con, dest, _transacted, Session.AUTO_ACKNOWLEDGE); - Thread t = new Thread((JMSSyncConsumer) consumer); - t.setName("JMSSyncConsumer-" + _count); - t.start(); - } - else - { - consumer = new JMSAsyncConsumer(String.valueOf(_count), con, dest, _transacted, Session.AUTO_ACKNOWLEDGE); - } - _consumers.put(_count, consumer); + this.parseOptions(); + _logFileName = _logFilePath + "/MessageConsumerTest_" + System.currentTimeMillis(); + + AMQConnection _connection = ConnectionUtility.getInstance().getConnection(); + _connection.start(); + Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(_connection,_destination) : new AMQTopic(_connection,_destination); + _session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); + _payload = TestMessageFactory.newBytesMessage(_session, _messageSize); + _consumer = _session.createConsumer(dest); + if(!_synchronous) + { + _consumer.setMessageListener(this); + } + _verifyOrder = Boolean.getBoolean("verifyOrder"); + + _startTime = System.currentTimeMillis(); + boolean run = true; + if(Boolean.getBoolean("collect_stats")) + { + printHeading(); + runReaper(); + } } - private void startTimerThread() + public void onMessage(Message message) { - _startTime = System.currentTimeMillis(); - if(Boolean.getBoolean("collect_stats")) - { - Thread t = new Thread(this); - t.setName("MessageConsumerTest-TimerThread"); - t.start(); - } try { - printSummary(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - - public void run() - { - boolean run = true; - printHeading(); - runReaper(); - try - { - while (run) + /* long msgId = Integer.parseInt(message.getJMSMessageID()); + if (_verifyOrder && _totalMsgCount+1 != msgId) { - Thread.sleep(_logDuration); - runReaper(); - - if (System.currentTimeMillis() + _gracePeriod - _startTime > _expiry) + _logger.error("Error : Message received out of order in JMSSyncConsumer:" + _id + " message id was " + msgId + " expected: " + _currentMsgCount+1); + }*/ + message = null; + _totalMsgCount ++; + _intervalCount++; + if(_intervalCount >= _logFrequency) + { + _intervalCount = 0; + if (Boolean.getBoolean("collect_stats")) { - // time to stop the test. - for (Integer id : _consumers.keySet()) - { - JMSConsumer consumer = _consumers.get(id); - consumer.stopConsuming(); - } runReaper(); - run = false; + } + if (System.currentTimeMillis() - _startTime >= _expiry) + { + _session.close(); + _connection.stop(); + printSummary(); + return; } } } - catch (InterruptedException e) + catch(Exception e) { - _logger.error("The timer thread exited", e); + e.printStackTrace(); } } @@ -119,16 +101,6 @@ public class MessageConsumerTest extends Options implements Runnable { try { - long totalMsgCountThisInterval = 0; - - for (Integer id : _consumers.keySet()) - { - JMSConsumer consumer = _consumers.get(id); - totalMsgCountThisInterval = totalMsgCountThisInterval + consumer.getCurrentMessageCount(); - - } - _totalMsgCount = _totalMsgCount + totalMsgCountThisInterval; - FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); StringBuffer buf = new StringBuffer(); Date d = new Date(System.currentTimeMillis()); @@ -137,8 +109,6 @@ public class MessageConsumerTest extends Options implements Runnable buf.append(d.getTime()).append(","); buf.append(_totalMsgCount).append(","); buf.append(_totalMsgCount*1000 /totaltime).append(","); - buf.append(totalMsgCountThisInterval).append(","); - buf.append(totalMsgCountThisInterval*1000/_logDuration).append(","); buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); buf.append("\n"); _memoryLog.write(buf.toString()); @@ -156,7 +126,7 @@ public class MessageConsumerTest extends Options implements Runnable try { FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); - String s = "Date/Time,Time (ms),total msg count,total rate (msg/sec),interval count,interval rate (msg/sec),memory"; + String s = "Date/Time,Time (ms),total msg count,total rate (msg/sec),memory"; _memoryLog.write(s); _memoryLog.close(); } @@ -166,33 +136,31 @@ public class MessageConsumerTest extends Options implements Runnable } } - private void printSummary() throws Exception + private void printSummary() { - if (Boolean.getBoolean("collect_stats")) + try { - for (Integer id : _consumers.keySet()) - { - JMSConsumer consumer = _consumers.get(id); - _totalMsgCount = _totalMsgCount + consumer.getCurrentMessageCount(); - } - } + long current = System.currentTimeMillis(); + double time = current - _startTime; + double ratio = _totalMsgCount*1000/time; + FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); - long current = System.currentTimeMillis(); - double time = current - _startTime; - double ratio = _totalMsgCount*1000/time; - FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); - - StringBuffer buf = new StringBuffer("MessageConsumerTest \n Test started at : "); - buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); - Date d = new Date(current); - buf.append(df.format(d)).append("\n Total Time taken (ms):"); - buf.append(time).append("\n Total messages sent:"); - buf.append(_totalMsgCount).append("\n consumer rate:"); - buf.append(ratio).append("\n"); - _summaryLog.write(buf.toString()); - System.out.println("---------- Test Ended -------------"); - _summaryLog.close(); + StringBuffer buf = new StringBuffer("MessageProducerTest \n Test started at : "); + buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); + Date d = new Date(current); + buf.append(df.format(d)).append("\n Total Time taken (ms):"); + buf.append(time).append("\n Total messages sent:"); + buf.append(_totalMsgCount).append("\n producer rate:"); + buf.append(ratio).append("\n"); + _summaryLog.write(buf.toString()); + System.out.println("---------- Test Ended -------------"); + _summaryLog.close(); + } + catch(Exception e) + { + e.printStackTrace(); + } } public static void main(String[] args) @@ -200,8 +168,7 @@ public class MessageConsumerTest extends Options implements Runnable try { MessageConsumerTest test = new MessageConsumerTest(); - test.start(); - test.startTimerThread(); + test.init(); } catch (Exception e) { diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java index 67a3aaa786..084e098cc3 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java @@ -7,119 +7,97 @@ import java.text.SimpleDateFormat; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import javax.jms.BytesMessage; import javax.jms.Connection; import javax.jms.Destination; +import javax.jms.MessageProducer; +import javax.jms.Session; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.message.TestMessageFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class MessageProducerTest extends Options implements Runnable +public class MessageProducerTest extends Options { private static final Logger _logger = LoggerFactory.getLogger(MessageProducerTest.class); private SimpleDateFormat df = new SimpleDateFormat("h:mm a"); - private Map _producers = new ConcurrentHashMap(); - private int _count; String _logFileName; long _startTime; long _totalMsgCount; + long _intervalCount; - public void start() throws Exception + private Connection _connection; + private Session _session; + private BytesMessage _payload; + private MessageProducer _producer; + + public void init() throws Exception { this.parseOptions(); - boolean useSameDest = true; _logFileName = _logFilePath + "/MessageProducerTest_" + System.currentTimeMillis(); - // use each destination with a different producer - if (_producerCount == destArray.length) - { - useSameDest = false; - } - for (;_count < _producerCount;_count++) - { - createAndStartProducer(useSameDest?destArray[0]:destArray[_count]); - } + AMQConnection _connection = ConnectionUtility.getInstance().getConnection(); + _connection.start(); + Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(_connection,_destination) : new AMQTopic(_connection,_destination); + _session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); + _payload = TestMessageFactory.newBytesMessage(_session, _messageSize); + _producer = _session.createProducer(dest); + // this should speedup the message producer + _producer.setDisableMessageTimestamp(true); } - private void createAndStartProducer(String routingKey)throws Exception - { - AMQConnection con = ConnectionUtility.getInstance().getConnection(); - con.start(); - Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(con,routingKey) : new AMQTopic(con,routingKey); - JMSProducer prod = new JMSProducer(String.valueOf(_count),(Connection)con, dest,_messageSize, _transacted); - Thread t = new Thread(prod); - t.setName("JMSProducer-"+_count); - t.start(); - _producers.put(_count, prod); - } - - private void startTimerThread() + public void run() { _startTime = System.currentTimeMillis(); + boolean run = true; if(Boolean.getBoolean("collect_stats")) { - Thread t = new Thread(this); - t.setName("MessageProducerTest-TimerThread"); - t.start(); - } - try - { - printSummary(); + printHeading(); + runReaper(); } - catch(Exception e) - { - e.printStackTrace(); - } - } - public void run() - { - boolean run = true; - printHeading(); - runReaper(); try { while (run) { - Thread.sleep(_logDuration); - runReaper(); + _payload.setJMSMessageID(String.valueOf(_totalMsgCount+1)); + _producer.send(_payload); + _totalMsgCount ++; + _intervalCount ++; - if (System.currentTimeMillis() - _startTime > _expiry) + // check every x messages to see if times up + if(_intervalCount >= _logFrequency) { - // time to stop the test. - for (Integer id : _producers.keySet()) + _intervalCount = 0; + if (Boolean.getBoolean("collect_stats")) { - JMSProducer producer = _producers.get(id); - producer.stopProducing(); + runReaper(); + } + if (System.currentTimeMillis() - _startTime >= _expiry) + { + // time to stop the test. + _session.close(); + _connection.stop(); + run = false; } - runReaper(); - run = false; } } } - catch (InterruptedException e) + catch (Exception e) { _logger.error("The timer thread exited", e); } + printSummary(); } public void runReaper() { try { - long totalMsgCountThisInterval = 0; - - for (Integer id : _producers.keySet()) - { - JMSProducer producer = _producers.get(id); - totalMsgCountThisInterval = totalMsgCountThisInterval + producer.getCurrentMessageCount(); - - } - _totalMsgCount = _totalMsgCount + totalMsgCountThisInterval; - FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); StringBuffer buf = new StringBuffer(); Date d = new Date(System.currentTimeMillis()); @@ -128,8 +106,6 @@ public class MessageProducerTest extends Options implements Runnable buf.append(d.getTime()).append(","); buf.append(_totalMsgCount).append(","); buf.append(_totalMsgCount*1000 /totaltime).append(","); - buf.append(totalMsgCountThisInterval).append(","); - buf.append(totalMsgCountThisInterval*1000/_logDuration).append(","); buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); buf.append("\n"); _memoryLog.write(buf.toString()); @@ -147,7 +123,7 @@ public class MessageProducerTest extends Options implements Runnable try { FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); - String s = "Date/Time,Time (ms),total msg count,total rate (msg/sec),interval count,interval rate (msg/sec),memory"; + String s = "Date/Time,Time (ms),total msg count,total rate (msg/sec),memory"; _memoryLog.write(s); _memoryLog.close(); } @@ -157,33 +133,31 @@ public class MessageProducerTest extends Options implements Runnable } } - private void printSummary() throws Exception + private void printSummary() { - if (Boolean.getBoolean("collect_stats")) + try { - for (Integer id : _producers.keySet()) - { - JMSProducer producer = _producers.get(id); - _totalMsgCount = _totalMsgCount + producer.getCurrentMessageCount(); - } + long current = System.currentTimeMillis(); + double time = current - _startTime; + double ratio = _totalMsgCount*1000/time; + FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); + + StringBuffer buf = new StringBuffer("MessageProducerTest \n Test started at : "); + buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); + Date d = new Date(current); + buf.append(df.format(d)).append("\n Total Time taken (ms):"); + buf.append(time).append("\n Total messages sent:"); + buf.append(_totalMsgCount).append("\n producer rate:"); + buf.append(ratio).append("\n"); + _summaryLog.write(buf.toString()); + System.out.println("---------- Test Ended -------------"); + _summaryLog.close(); + } + catch(Exception e) + { + e.printStackTrace(); } - - long current = System.currentTimeMillis(); - double time = current - _startTime; - double ratio = _totalMsgCount*1000/time; - FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); - - StringBuffer buf = new StringBuffer("MessageProducerTest \n Test started at : "); - buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); - Date d = new Date(current); - buf.append(df.format(d)).append("\n Total Time taken (ms):"); - buf.append(time).append("\n Total messages sent:"); - buf.append(_totalMsgCount).append("\n producer rate:"); - buf.append(ratio).append("\n"); - _summaryLog.write(buf.toString()); - System.out.println("---------- Test Ended -------------"); - _summaryLog.close(); } public static void main(String[] args) @@ -191,8 +165,8 @@ public class MessageProducerTest extends Options implements Runnable try { MessageProducerTest test = new MessageProducerTest(); - test.start(); - test.startTimerThread(); + test.init(); + test.run(); } catch(Exception e) { diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java index 2d04426794..6f68d5fedc 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java @@ -5,11 +5,9 @@ public class Options int _messageSize; boolean _transacted; boolean _synchronous; - String[] destArray; - int _producerCount; - int _consumerCount; + String _destination; long _expiry; - long _logDuration; + long _logFrequency; String _logFilePath; /** @@ -17,8 +15,6 @@ public class Options * -DmessageSize * -DuseQueue * -Dtransacted - * -DproducerCount - * -DconsumerCount * -Ddestinations * -DlogFilePath * -Duration=1H,30M,10S @@ -27,21 +23,16 @@ public class Options public void parseOptions() { _messageSize = Integer.parseInt(System.getProperty("messageSize","100")); - _synchronous = Boolean.parseBoolean( System.getProperty("synchronous", "false")); _transacted = false; - String destinations = System.getProperty("destinations"); - destArray = destinations.split(","); - _producerCount = Integer.parseInt(System.getProperty("producerCount","1")); - _consumerCount = Integer.parseInt(System.getProperty("consumerCount","1")); - _logDuration = Long.parseLong(System.getProperty("logDuration","10")); - _logDuration = _logDuration*1000*60; + _destination = System.getProperty("destinations"); + _logFrequency = Long.parseLong(System.getProperty("logDuration","10")); _logFilePath = System.getProperty("logFilePath"); _expiry = getExpiry(); System.out.println("============= Test Data ==================="); - System.out.println("Total no of producers : " + _producerCount); - System.out.println(_synchronous? "Total no of synchronous consumers : " : "Total no of asynchronous consumers :" + _consumerCount); - System.out.println("Log Frequency in mins : " + _logDuration/(1000*60)); + System.out.println("Destination : " + _destination); + System.out.println("Collect stats : " + Boolean.getBoolean("collect_stats")); + System.out.println("Log Frequency in msgs : " + _logFrequency); System.out.println("Log file path : " + _logFilePath); System.out.println("Test Duration : " + printTestDuration()); System.out.println("============= /Test Data ==================="); -- cgit v1.2.1 From 609e2db9fe6b2968ec62bd1d7aa4f9a2dfd5aa21 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Thu, 29 Nov 2007 23:21:26 +0000 Subject: Modified the scripts And made the default log frequency to every 1000 msgs git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@599624 13f79535-47bb-0310-9956-ffa450edef68 --- .../perftests/src/main/java/org/apache/qpid/client/perf/Options.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java index 6f68d5fedc..e9a86b8014 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java @@ -25,7 +25,7 @@ public class Options _messageSize = Integer.parseInt(System.getProperty("messageSize","100")); _transacted = false; _destination = System.getProperty("destinations"); - _logFrequency = Long.parseLong(System.getProperty("logDuration","10")); + _logFrequency = Long.parseLong(System.getProperty("logFrequency","1000")); _logFilePath = System.getProperty("logFilePath"); _expiry = getExpiry(); -- cgit v1.2.1 From 2550df4bf1eafbcf25caad2dc235bc9c08d3c750 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Thu, 29 Nov 2007 23:47:31 +0000 Subject: Printing summary before closing session, as this sometimes results in an error git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@599637 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java index d820b22de9..9700c1733e 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java @@ -84,9 +84,9 @@ public class MessageConsumerTest extends Options implements MessageListener } if (System.currentTimeMillis() - _startTime >= _expiry) { + printSummary(); _session.close(); _connection.stop(); - printSummary(); return; } } -- cgit v1.2.1 From 53099f29bc6c4b0a66475ba39c0666ca528bf487 Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Fri, 30 Nov 2007 08:00:22 +0000 Subject: added interval rate git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@599725 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/perf/MessageConsumerTest.java | 38 ++++++++++------------ .../qpid/client/perf/MessageProducerTest.java | 25 ++++++++------ .../java/org/apache/qpid/client/perf/Options.java | 2 +- 3 files changed, 33 insertions(+), 32 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java index 9700c1733e..a618a6599d 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java @@ -5,19 +5,15 @@ import java.io.IOException; import java.sql.Date; import java.text.SimpleDateFormat; -import javax.jms.BytesMessage; -import javax.jms.Connection; import javax.jms.Destination; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; -import javax.jms.MessageProducer; import javax.jms.Session; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.message.TestMessageFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,34 +24,28 @@ public class MessageConsumerTest extends Options implements MessageListener String _logFileName; long _startTime; + long _intervalStartTime; long _totalMsgCount; long _intervalCount; - private Connection _connection; + private AMQConnection _connection; private Session _session; - private BytesMessage _payload; - private MessageConsumer _consumer; - private boolean _verifyOrder = false; public void init() throws Exception { this.parseOptions(); _logFileName = _logFilePath + "/MessageConsumerTest_" + System.currentTimeMillis(); - - AMQConnection _connection = ConnectionUtility.getInstance().getConnection(); + _connection = ConnectionUtility.getInstance().getConnection(); _connection.start(); Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(_connection,_destination) : new AMQTopic(_connection,_destination); _session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); - _payload = TestMessageFactory.newBytesMessage(_session, _messageSize); - _consumer = _session.createConsumer(dest); - if(!_synchronous) + MessageConsumer _consumer = _session.createConsumer(dest); + if(!_synchronous) { _consumer.setMessageListener(this); } - _verifyOrder = Boolean.getBoolean("verifyOrder"); _startTime = System.currentTimeMillis(); - boolean run = true; if(Boolean.getBoolean("collect_stats")) { printHeading(); @@ -72,7 +62,6 @@ public class MessageConsumerTest extends Options implements MessageListener { _logger.error("Error : Message received out of order in JMSSyncConsumer:" + _id + " message id was " + msgId + " expected: " + _currentMsgCount+1); }*/ - message = null; _totalMsgCount ++; _intervalCount++; if(_intervalCount >= _logFrequency) @@ -87,7 +76,6 @@ public class MessageConsumerTest extends Options implements MessageListener printSummary(); _session.close(); _connection.stop(); - return; } } } @@ -101,19 +89,27 @@ public class MessageConsumerTest extends Options implements MessageListener { try { - FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); + FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); StringBuffer buf = new StringBuffer(); Date d = new Date(System.currentTimeMillis()); - double totaltime = d.getTime() - _startTime; + long currentTime = d.getTime(); + long intervalTime = currentTime - _intervalStartTime; + long totalTime = currentTime - _startTime; buf.append(df.format(d)).append(","); buf.append(d.getTime()).append(","); - buf.append(_totalMsgCount).append(","); - buf.append(_totalMsgCount*1000 /totaltime).append(","); + buf.append(" total Msg Count: ").append(_totalMsgCount).append(","); + if(totalTime > 0 ) + buf.append(" rate: ").append(_totalMsgCount * 1000 / totalTime); + buf.append(","); + buf.append(" interval Count: ").append(_intervalCount).append(","); + if(intervalTime > 0 ) + buf.append(" interval rate: ").append(_intervalCount * 1000 / intervalTime).append(","); buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); buf.append("\n"); _memoryLog.write(buf.toString()); _memoryLog.close(); System.out.println(buf); + _intervalStartTime = d.getTime(); } catch (Exception e) { diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java index 084e098cc3..4398b28131 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java @@ -4,11 +4,8 @@ import java.io.FileWriter; import java.io.IOException; import java.sql.Date; import java.text.SimpleDateFormat; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import javax.jms.BytesMessage; -import javax.jms.Connection; import javax.jms.Destination; import javax.jms.MessageProducer; import javax.jms.Session; @@ -27,10 +24,11 @@ public class MessageProducerTest extends Options String _logFileName; long _startTime; + long _intervalStartTime; long _totalMsgCount; long _intervalCount; - private Connection _connection; + private AMQConnection _connection; private Session _session; private BytesMessage _payload; private MessageProducer _producer; @@ -39,8 +37,7 @@ public class MessageProducerTest extends Options { this.parseOptions(); _logFileName = _logFilePath + "/MessageProducerTest_" + System.currentTimeMillis(); - - AMQConnection _connection = ConnectionUtility.getInstance().getConnection(); + _connection = ConnectionUtility.getInstance().getConnection(); _connection.start(); Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(_connection,_destination) : new AMQTopic(_connection,_destination); _session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); @@ -72,10 +69,10 @@ public class MessageProducerTest extends Options // check every x messages to see if times up if(_intervalCount >= _logFrequency) { - _intervalCount = 0; if (Boolean.getBoolean("collect_stats")) { runReaper(); + _intervalCount = 0; } if (System.currentTimeMillis() - _startTime >= _expiry) { @@ -101,16 +98,24 @@ public class MessageProducerTest extends Options FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); StringBuffer buf = new StringBuffer(); Date d = new Date(System.currentTimeMillis()); - double totaltime = d.getTime() - _startTime; + long currentTime = d.getTime(); + long intervalTime = currentTime - _intervalStartTime; + long totalTime = currentTime - _startTime; buf.append(df.format(d)).append(","); buf.append(d.getTime()).append(","); - buf.append(_totalMsgCount).append(","); - buf.append(_totalMsgCount*1000 /totaltime).append(","); + buf.append(" total Msg Count: ").append(_totalMsgCount).append(","); + if(totalTime > 0 ) + buf.append(" rate: ").append(_totalMsgCount * 1000 / totalTime); + buf.append(","); + buf.append(" interval Count: ").append(_intervalCount).append(","); + if(intervalTime > 0 ) + buf.append(" interval rate: ").append(_intervalCount * 1000 / intervalTime).append(","); buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); buf.append("\n"); _memoryLog.write(buf.toString()); _memoryLog.close(); System.out.println(buf); + _intervalStartTime = d.getTime(); } catch (Exception e) { diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java index e9a86b8014..4fc8f036ff 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java @@ -25,7 +25,7 @@ public class Options _messageSize = Integer.parseInt(System.getProperty("messageSize","100")); _transacted = false; _destination = System.getProperty("destinations"); - _logFrequency = Long.parseLong(System.getProperty("logFrequency","1000")); + _logFrequency = Long.parseLong(System.getProperty("logFrequency","10000")); _logFilePath = System.getProperty("logFilePath"); _expiry = getExpiry(); -- cgit v1.2.1 From e7d6a487daf73db3500cd07ac4583dfdfd4bc691 Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Fri, 30 Nov 2007 12:56:14 +0000 Subject: added latency tests git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@599810 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/latency/MessageConsumer.java | 127 +++++++++++++++++++++ .../qpid/client/latency/MessageProducer.java | 104 +++++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageConsumer.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageConsumer.java new file mode 100644 index 0000000000..fafcbace67 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageConsumer.java @@ -0,0 +1,127 @@ +/* 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.qpid.client.latency; + +import org.apache.qpid.requestreply.InitialContextHelper; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.perf.Options; +import org.apache.qpid.server.queue.AMQQueueMBean; + +import javax.jms.*; + +/** + * + * + */ +public class MessageConsumer extends Options implements MessageListener +{ + private javax.jms.MessageProducer _producer; + private AMQConnection _connection; + private final Object _lock = new Object(); + private Session _session; + private int _receivedMessages = 0; + private long _timeFirstMessage; + private long _timeLastMessage; + private void init() + { + this.parseOptions(); + try + { + ConnectionFactory factory = (ConnectionFactory) InitialContextHelper.getInitialContext("").lookup("local"); + _connection = (AMQConnection) factory.createConnection("guest","guest"); + _session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); + Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(_connection,_destination) : new AMQTopic( + _connection,_destination); + Destination syncQueue = new AMQQueue(_connection, "syncQueue"); + _producer = _session.createProducer(syncQueue); + // this should speedup the message producer + _producer.setDisableMessageTimestamp(true); + javax.jms.MessageConsumer consumer = _session.createConsumer(dest); + consumer.setMessageListener(this); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + private void run() + { + try + { + synchronized(_lock) + { + _connection.start(); + try + { + _lock.wait(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + // send sync message; + _producer.send(_session.createMessage()); + System.out.println("Time to receive " + _logFrequency + " messages is: " + (_timeLastMessage - _timeFirstMessage) ); + double rate = _logFrequency / ((_timeLastMessage - _timeFirstMessage) *1.0) *1000 ; + System.out.println("The rate is " + rate + " msg/s" ); + double latency = ((_timeLastMessage - _timeFirstMessage) *1.0) / _logFrequency; + System.out.println("The latency is " + latency + " milli secs" ); + _connection.close(); + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + + public void onMessage(Message message) + { + if( _receivedMessages == 0) + { + _timeFirstMessage = System.currentTimeMillis(); + } + _receivedMessages++; + if( _receivedMessages == _logFrequency) + { + _timeLastMessage = System.currentTimeMillis(); + synchronized(_lock) + { + _lock.notify(); + } + } + } + + public static void main(String[] args) + { + try + { + MessageConsumer test = new MessageConsumer(); + test.init(); + test.run(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java new file mode 100644 index 0000000000..10b8833a8b --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java @@ -0,0 +1,104 @@ +/* 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.qpid.client.latency; + +import org.apache.qpid.client.perf.Options; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.requestreply.InitialContextHelper; + +import javax.jms.*; +import java.util.Date; + +/** + * + * + */ +public class MessageProducer extends Options +{ + private BytesMessage _payload; + private javax.jms.MessageProducer _producer; + private javax.jms.MessageConsumer _consumer; + private AMQConnection _connection; + private void init() + { + this.parseOptions(); + try + { + ConnectionFactory factory = (ConnectionFactory) InitialContextHelper.getInitialContext("").lookup("local"); + _connection = (AMQConnection) factory.createConnection(); + _connection.start(); + Session session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); + _payload = TestMessageFactory.newBytesMessage(session, _messageSize); + Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(_connection,_destination) : new AMQTopic( + _connection,_destination); + Destination syncQueue = new AMQQueue(_connection, "syncQueue"); + _producer = session.createProducer(dest); + _consumer = session.createConsumer(syncQueue); + // this should speedup the message producer + _producer.setDisableMessageTimestamp(true); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + private void run() + { + try + { + long startTime = System.currentTimeMillis(); + for(int i =0; i < _logFrequency; i++ ) + { + _producer.send(_payload); + } + long endProducing = System.currentTimeMillis(); + double throughput = (_logFrequency * 1000.0) / (endProducing - startTime); + System.out.println("The producer throughput is: " + throughput + " msg/s"); + // now wait for the sync message + _consumer.receive(); + // this is done + long endTime = System.currentTimeMillis(); + System.out.println("Time to send and receive " + _logFrequency + " messages is: " + (endTime - startTime) ); + double latency = ( (endTime - startTime) * 1.0) /_logFrequency; + System.out.println("The latency is " + latency + " milli secs" ); + _connection.close(); + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + + public static void main(String[] args) + { + try + { + MessageProducer test = new MessageProducer(); + test.init(); + test.run(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } +} -- cgit v1.2.1 From d8409a1fa9018c8fdc3cd030b1a4973d76836814 Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Fri, 30 Nov 2007 16:45:20 +0000 Subject: added latency tests git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@599868 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/client/perf/Options.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java index 4fc8f036ff..c0f51738db 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java @@ -2,13 +2,13 @@ package org.apache.qpid.client.perf; public class Options { - int _messageSize; - boolean _transacted; - boolean _synchronous; - String _destination; - long _expiry; - long _logFrequency; - String _logFilePath; + public int _messageSize; + public boolean _transacted; + public boolean _synchronous; + public String _destination; + public long _expiry; + public long _logFrequency; + public String _logFilePath; /** * System props @@ -24,7 +24,7 @@ public class Options { _messageSize = Integer.parseInt(System.getProperty("messageSize","100")); _transacted = false; - _destination = System.getProperty("destinations"); + _destination = System.getProperty("destination", "foo"); _logFrequency = Long.parseLong(System.getProperty("logFrequency","10000")); _logFilePath = System.getProperty("logFilePath"); _expiry = getExpiry(); -- cgit v1.2.1 From b4953dd742da8c4729632ce2b6d99ebb0c8f9b32 Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Wed, 19 Dec 2007 09:43:39 +0000 Subject: chnaged to use jndi git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@605489 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/latency/MessageConsumer.java | 14 +++++---- .../qpid/client/latency/MessageProducer.java | 34 +++++++++++++++------- 2 files changed, 31 insertions(+), 17 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageConsumer.java index fafcbace67..80f965eae5 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageConsumer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageConsumer.java @@ -17,14 +17,15 @@ */ package org.apache.qpid.client.latency; -import org.apache.qpid.requestreply.InitialContextHelper; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; import org.apache.qpid.client.perf.Options; -import org.apache.qpid.server.queue.AMQQueueMBean; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.requestreply.InitialContextHelper; import javax.jms.*; +import javax.naming.Context; /** * @@ -44,12 +45,13 @@ public class MessageConsumer extends Options implements MessageListener this.parseOptions(); try { - ConnectionFactory factory = (ConnectionFactory) InitialContextHelper.getInitialContext("").lookup("local"); + Context context = InitialContextHelper.getInitialContext(""); + ConnectionFactory factory = (ConnectionFactory) context.lookup("local"); _connection = (AMQConnection) factory.createConnection("guest","guest"); _session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); - Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(_connection,_destination) : new AMQTopic( - _connection,_destination); - Destination syncQueue = new AMQQueue(_connection, "syncQueue"); + Destination dest = Boolean.getBoolean("useQueue")? (Destination) context.lookup("testQueue") : + (Destination) context.lookup("testTopic"); + Destination syncQueue = (Destination) context.lookup("syncQueue"); _producer = _session.createProducer(syncQueue); // this should speedup the message producer _producer.setDisableMessageTimestamp(true); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java index 10b8833a8b..3e830f2abe 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java @@ -17,15 +17,14 @@ */ package org.apache.qpid.client.latency; -import org.apache.qpid.client.perf.Options; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQTopic; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.client.perf.Options; import org.apache.qpid.requestreply.InitialContextHelper; +import org.apache.qpidity.transport.network.nio.NioSender; import javax.jms.*; -import java.util.Date; +import javax.naming.Context; /** * @@ -42,18 +41,20 @@ public class MessageProducer extends Options this.parseOptions(); try { - ConnectionFactory factory = (ConnectionFactory) InitialContextHelper.getInitialContext("").lookup("local"); - _connection = (AMQConnection) factory.createConnection(); - _connection.start(); + Context context = InitialContextHelper.getInitialContext(""); + ConnectionFactory factory = (ConnectionFactory) context.lookup("local"); + _connection = (AMQConnection) factory.createConnection("guest","guest"); + Destination dest = Boolean.getBoolean("useQueue")? (Destination) context.lookup("testQueue") : + (Destination) context.lookup("testTopic"); + Destination syncQueue = (Destination) context.lookup("syncQueue"); + _connection.start(); Session session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); _payload = TestMessageFactory.newBytesMessage(session, _messageSize); - Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(_connection,_destination) : new AMQTopic( - _connection,_destination); - Destination syncQueue = new AMQQueue(_connection, "syncQueue"); _producer = session.createProducer(dest); _consumer = session.createConsumer(syncQueue); // this should speedup the message producer _producer.setDisableMessageTimestamp(true); + System.out.println("Init end" ); } catch (Exception e) { @@ -65,14 +66,25 @@ public class MessageProducer extends Options { try { + System.out.println("Sending " + _logFrequency + " messages"); + + NioSender.setStartBatching(); long startTime = System.currentTimeMillis(); for(int i =0; i < _logFrequency; i++ ) { - _producer.send(_payload); + _producer.send(_payload, DeliveryMode.PERSISTENT, Message.DEFAULT_PRIORITY, 0); } long endProducing = System.currentTimeMillis(); double throughput = (_logFrequency * 1000.0) / (endProducing - startTime); System.out.println("The producer throughput is: " + throughput + " msg/s"); + + // startTime = System.currentTimeMillis(); + // NioSender.purge(); + // endProducing = System.currentTimeMillis(); + // throughput = (_logFrequency * 1000.0) / (endProducing - startTime); + // System.out.println("The NIO throughput is: " + throughput + " msg/s"); + + // now wait for the sync message _consumer.receive(); // this is done -- cgit v1.2.1 From 7ca935fc15a93b95df28087207f32773de4f8551 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Thu, 3 Jan 2008 20:25:58 +0000 Subject: fixed compile error in MessageProducer.java git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@608618 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/client/latency/MessageProducer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java index 3e830f2abe..c084a55bcc 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java @@ -68,7 +68,7 @@ public class MessageProducer extends Options { System.out.println("Sending " + _logFrequency + " messages"); - NioSender.setStartBatching(); + // NioSender.setStartBatching(); long startTime = System.currentTimeMillis(); for(int i =0; i < _logFrequency; i++ ) { -- cgit v1.2.1 From f16667452555db6516ab047c41fdf7a597572391 Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Wed, 16 Jan 2008 22:21:07 +0000 Subject: Fixed various compilation errors git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@612593 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/client/perf/MessageConsumerTest.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java index a618a6599d..1124e070a1 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java @@ -40,11 +40,7 @@ public class MessageConsumerTest extends Options implements MessageListener Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(_connection,_destination) : new AMQTopic(_connection,_destination); _session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); MessageConsumer _consumer = _session.createConsumer(dest); - if(!_synchronous) - { - _consumer.setMessageListener(this); - } - + _consumer.setMessageListener(this); _startTime = System.currentTimeMillis(); if(Boolean.getBoolean("collect_stats")) { -- cgit v1.2.1 From 4736e936d0e876fd953071b3262644a745d82eca Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Mon, 21 Jan 2008 09:20:54 +0000 Subject: Added new perf test for topic (based on Andy's usecase) git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@613807 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/client/topic/Client.java | 192 +++++++++++++++++++++ .../java/org/apache/qpid/client/topic/Server.java | 103 +++++++++++ .../org/apache/qpid/client/topic/topic.properties | 24 +++ 3 files changed, 319 insertions(+) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Client.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Server.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/topic.properties (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Client.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Client.java new file mode 100644 index 0000000000..a9bdc61e0e --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Client.java @@ -0,0 +1,192 @@ +/* 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.qpid.client.topic; + +import org.apache.qpid.client.message.TestMessageFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.jms.*; +import java.util.Properties; +import java.util.Random; +import java.util.List; +import java.util.ArrayList; + +public class Client +{ + /** + * This class logger + */ + private static final Logger _logger=LoggerFactory.getLogger(Client.class); + + private long _messagesProduced=0; + private final Object _lock=new Object(); + private Message _message; + private List _runners=new ArrayList(); + + + /** + * Run the message consumer example. + * + * @param args Command line arguments. + */ + public static void main(String[] args) + { + Client syncConsumer=new Client(); + int firstArg=120; + if (args.length > 0) + { + try + { + firstArg=Integer.parseInt(args[0]); + } + catch (NumberFormatException e) + { + _logger.warn("Argument must be an integer, running for 2 minutes"); + } + } + syncConsumer.runClient(firstArg); + } + + + void runClient(long duration) + { + try + { + // Load JNDI properties + Properties properties=new Properties(); + properties.load(this.getClass().getResourceAsStream("topic.properties")); + + //Create the initial context + Context ctx=new InitialContext(properties); + + // Lookup the connection factory + ConnectionFactory conFac=(ConnectionFactory) ctx.lookup("qpidConnectionfactory"); + // create the connection + Connection connection=conFac.createConnection(); + + connection.setExceptionListener(new ExceptionListener() + { + public void onException(JMSException jmse) + { + // The connection may have broken invoke reconnect code if available. + // The connection may have broken invoke reconnect code if available. + System.err.println("Received an exception through the ExceptionListener"); + System.exit(0); + } + }); + + // Now the messageConsumer is set up we can start the connection + connection.start(); + + // Create a session on the connection + // This session is a default choice of non-transacted and uses the auto acknowledge feature of a session. + Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _message=TestMessageFactory.newBytesMessage(session, 1024); + + Random random=new Random(); + long testDuration=0; + long totalMessagesProduced; + long messagesProducedLastInterval=0; + long intervalThroughput; + long totalThroughput; + long numProducers=1; + startNewProducer(session, random); + while (testDuration < duration) + { + // every 5 second creates a thread an print the throughput + synchronized (_lock) + { + _lock.wait(5000); + totalMessagesProduced=_messagesProduced; + } + testDuration=testDuration + 5; + intervalThroughput=(totalMessagesProduced - messagesProducedLastInterval) / 5; + totalThroughput=totalMessagesProduced / testDuration; + messagesProducedLastInterval=totalMessagesProduced; + _logger.info("Number of producers " + numProducers + " | This interval throughput = " + + intervalThroughput + " | Total throughput = " + totalThroughput); + startNewProducer(session, random); + numProducers++; + } + // stop all the producers + for (Runner runner : _runners) + { + runner.stop(); + } + + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + private void startNewProducer(Session session, Random random) + throws JMSException + { + // select a random topic + int topicNumber=random.nextInt(50); + Topic topic=session.createTopic("topic-" + topicNumber); + MessageProducer prod=session.createProducer(topic); + Runner runner=new Runner(prod); + _runners.add(runner); + Thread thread=new Thread(runner); + thread.start(); + } + + private class Runner implements Runnable + { + MessageProducer _prod; + boolean _produce=true; + + private Runner(MessageProducer prod) + { + _prod=prod; + } + + public void run() + { + while (_produce) + { + try + { + _prod.send(_message, DeliveryMode.PERSISTENT, Message.DEFAULT_PRIORITY, + Message.DEFAULT_TIME_TO_LIVE); + synchronized (_lock) + { + _messagesProduced++; + } + } + catch (Exception e) + { + e.printStackTrace(); + _produce=false; + } + } + } + + public void stop() + { + _produce=false; + } + } + +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Server.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Server.java new file mode 100644 index 0000000000..aeebe5976e --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Server.java @@ -0,0 +1,103 @@ +/* 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.qpid.client.topic; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.naming.Context; +import javax.naming.InitialContext; + +import javax.jms.*; +import java.util.Properties; + + +public class Server +{ + /** + * This class logger + */ + private static final Logger _logger =LoggerFactory.getLogger(Server.class); + + + public static void main(String[] args) + { + (new Server()).runServer(); + } + + void runServer() + { + try + { + // Load JNDI properties + Properties properties=new Properties(); + properties.load(this.getClass().getResourceAsStream("topic.properties")); + + //Create the initial context + Context ctx=new InitialContext(properties); + + // Lookup the connection factory + ConnectionFactory conFac=(ConnectionFactory) ctx.lookup("qpidConnectionfactory"); + // create the connection + Connection connection=conFac.createConnection(); + + connection.setExceptionListener(new ExceptionListener() + { + public void onException(JMSException jmse) + { + // The connection may have broken invoke reconnect code if available. + // The connection may have broken invoke reconnect code if available. + _logger.warn("Received an exception through the ExceptionListener"); + System.exit(0); + } + }); + + // Create a session on the connection + // This session is a default choice of non-transacted and uses the auto acknowledge feature of a session. + Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + for (int i=0; i < 50; i++) + { + Topic topic=session.createTopic("topic-" + i); + TopicSubscriber dursub=session.createDurableSubscriber(topic, "durable-" + i); + dursub.setMessageListener(new MyListener()); + } + + // Now the messageConsumer is set up we can start the connection + connection.start(); + synchronized (connection) + { + connection.wait(); + } + + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + private class MyListener implements MessageListener + { + public void onMessage(Message message) + { + _logger.debug("Received a message"); + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/topic.properties b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/topic.properties new file mode 100644 index 0000000000..070054cf5b --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/topic.properties @@ -0,0 +1,24 @@ +# +# 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. +# +java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory + +#connectionfactory.local = amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672' + +# A 0.10 connection factory +connectionfactory.qpidConnectionfactory = qpid:password=pass;username=name@tcp:localhost:5672 -- cgit v1.2.1 From 6041c76cc5048f13f62053e520390a1b90c7ea0c Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Mon, 21 Jan 2008 13:33:00 +0000 Subject: Imporved topic perf tests git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@613883 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/client/topic/Client.java | 26 +++++-- .../java/org/apache/qpid/client/topic/Server.java | 84 +++++++++++++++++++--- .../org/apache/qpid/client/topic/topic.properties | 4 +- 3 files changed, 100 insertions(+), 14 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Client.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Client.java index a9bdc61e0e..4a726c19ea 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Client.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Client.java @@ -28,6 +28,7 @@ import java.util.Properties; import java.util.Random; import java.util.List; import java.util.ArrayList; +import java.io.FileWriter; public class Client { @@ -74,6 +75,9 @@ public class Client Properties properties=new Properties(); properties.load(this.getClass().getResourceAsStream("topic.properties")); + String logFilePath = System.getProperty("logFilePath", "./"); + FileWriter file = new FileWriter(logFilePath + "client-" + System.currentTimeMillis() + ".cvs",true); + //Create the initial context Context ctx=new InitialContext(properties); @@ -99,6 +103,14 @@ public class Client // Create a session on the connection // This session is a default choice of non-transacted and uses the auto acknowledge feature of a session. Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue queueCompleted = session.createQueue("completed"); + Queue queueStarted = session.createQueue("started"); + MessageProducer prod = session.createProducer(queueCompleted); + MessageConsumer cons = session.createConsumer(queueStarted); + cons.receive(); + _logger.info("Starting producing messages"); + _message=TestMessageFactory.newBytesMessage(session, 1024); Random random=new Random(); @@ -108,6 +120,7 @@ public class Client long intervalThroughput; long totalThroughput; long numProducers=1; + String info; startNewProducer(session, random); while (testDuration < duration) { @@ -121,17 +134,21 @@ public class Client intervalThroughput=(totalMessagesProduced - messagesProducedLastInterval) / 5; totalThroughput=totalMessagesProduced / testDuration; messagesProducedLastInterval=totalMessagesProduced; - _logger.info("Number of producers " + numProducers + " | This interval throughput = " + - intervalThroughput + " | Total throughput = " + totalThroughput); + info = "Number of producers " + numProducers + " | This interval throughput = " + + intervalThroughput + " | Total throughput = " + totalThroughput; + _logger.info(info); + file.write(info + "\n"); startNewProducer(session, random); numProducers++; } + file.close(); // stop all the producers for (Runner runner : _runners) { runner.stop(); } - + _logger.info("Stopping server"); + prod.send(session.createTextMessage("stop")); } catch (Exception e) { @@ -144,11 +161,13 @@ public class Client { // select a random topic int topicNumber=random.nextInt(50); + _logger.info("creating producer for topic: topic- " + topicNumber); Topic topic=session.createTopic("topic-" + topicNumber); MessageProducer prod=session.createProducer(topic); Runner runner=new Runner(prod); _runners.add(runner); Thread thread=new Thread(runner); + thread.setDaemon(true); thread.start(); } @@ -156,7 +175,6 @@ public class Client { MessageProducer _prod; boolean _produce=true; - private Runner(MessageProducer prod) { _prod=prod; diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Server.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Server.java index aeebe5976e..883a7465a1 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Server.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Server.java @@ -26,6 +26,7 @@ import javax.naming.InitialContext; import javax.jms.*; import java.util.Properties; +import java.io.FileWriter; public class Server @@ -33,9 +34,14 @@ public class Server /** * This class logger */ - private static final Logger _logger =LoggerFactory.getLogger(Server.class); + private static final Logger _logger=LoggerFactory.getLogger(Server.class); + private final Object _lock=new Object(); + private long _numMessages=0; + public FileWriter _file; + public boolean _running=true; + public static void main(String[] args) { (new Server()).runServer(); @@ -49,6 +55,9 @@ public class Server Properties properties=new Properties(); properties.load(this.getClass().getResourceAsStream("topic.properties")); + String logFilePath=System.getProperty("logFilePath", "./"); + _file=new FileWriter(logFilePath + "server-" + System.currentTimeMillis() + ".cvs", true); + //Create the initial context Context ctx=new InitialContext(properties); @@ -70,10 +79,11 @@ public class Server // Create a session on the connection // This session is a default choice of non-transacted and uses the auto acknowledge feature of a session. - Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + // Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE); for (int i=0; i < 50; i++) { + Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Topic topic=session.createTopic("topic-" + i); TopicSubscriber dursub=session.createDurableSubscriber(topic, "durable-" + i); dursub.setMessageListener(new MyListener()); @@ -81,11 +91,31 @@ public class Server // Now the messageConsumer is set up we can start the connection connection.start(); - synchronized (connection) - { - connection.wait(); - } - + _logger.info("Ready to consume messages"); + // listen for the termination message + Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queueCompleted=session.createQueue("completed"); + Queue queueStarted=session.createQueue("started"); + MessageProducer prod=session.createProducer(queueStarted); + + Thread logger=new Thread(new MyLogger()); + logger.setDaemon(true); + logger.start(); + + prod.send(session.createTextMessage("start")); + long startTime=System.currentTimeMillis(); + MessageConsumer cons=session.createConsumer(queueCompleted); + cons.receive(); + + _running=false; + + long endTime=System.currentTimeMillis(); + session.close(); + _logger.info("Received " + _numMessages); + _file.write("Received " + _numMessages + "\n"); + _logger.info("Throughput " + _numMessages / (endTime - startTime) * 1000 + "msg/s"); + _file.write("Throughput " + _numMessages / (endTime - startTime) * 1000 + "msg/s"); + _file.close(); } catch (Exception e) { @@ -97,7 +127,45 @@ public class Server { public void onMessage(Message message) { - _logger.debug("Received a message"); + synchronized (_lock) + { + _numMessages++; + /*if(_numMessages % 1000 == 0) + { + _logger.info("received: " + _numMessages); + } */ + } + } + } + + private class MyLogger implements Runnable + { + public void run() + { + long endTime=0; + while (_running) + { + synchronized (_lock) + { + try + { + _lock.wait(5000); + if (_running) + { + endTime=endTime + 5; + String s="Throughput " + _numMessages / endTime + " msg/s"; + _logger.info(s); + _file.write(s + "\n"); + } + + } + catch (Exception e) + { + e.printStackTrace(); + } + + } + } } } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/topic.properties b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/topic.properties index 070054cf5b..cff5275e36 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/topic.properties +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/topic.properties @@ -18,7 +18,7 @@ # java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory -#connectionfactory.local = amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672' +connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672' # A 0.10 connection factory -connectionfactory.qpidConnectionfactory = qpid:password=pass;username=name@tcp:localhost:5672 +#connectionfactory.qpidConnectionfactory = qpid:password=pass;username=name@tcp:localhost:5672 -- cgit v1.2.1 From d8988a8acd974f58545bacb52496bb9dcc9fae6d Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Wed, 23 Apr 2008 23:50:34 +0000 Subject: Delete stuff that's just going to get synced from M2.x git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@651111 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/latency/MessageConsumer.java | 129 -- .../qpid/client/latency/MessageProducer.java | 116 -- .../qpid/client/message/TestMessageFactory.java | 109 -- .../apache/qpid/client/perf/ConnectionUtility.java | 50 - .../qpid/client/perf/MessageConsumerTest.java | 171 -- .../qpid/client/perf/MessageProducerTest.java | 182 --- .../java/org/apache/qpid/client/perf/Options.java | 105 -- .../java/org/apache/qpid/client/topic/Client.java | 210 --- .../java/org/apache/qpid/client/topic/Server.java | 171 -- .../org/apache/qpid/client/topic/topic.properties | 24 - .../org/apache/qpid/ping/PingAsyncTestPerf.java | 292 ---- .../main/java/org/apache/qpid/ping/PingClient.java | 107 -- .../org/apache/qpid/ping/PingDurableClient.java | 451 ----- .../org/apache/qpid/ping/PingLatencyTestPerf.java | 314 ---- .../org/apache/qpid/ping/PingSendOnlyClient.java | 92 -- .../java/org/apache/qpid/ping/PingTestPerf.java | 196 --- .../qpid/requestreply/InitialContextHelper.java | 55 - .../apache/qpid/requestreply/PingPongBouncer.java | 392 ----- .../apache/qpid/requestreply/PingPongProducer.java | 1717 -------------------- .../apache/qpid/requestreply/PingPongTestPerf.java | 251 --- 20 files changed, 5134 deletions(-) delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageConsumer.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/ConnectionUtility.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Client.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Server.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/topic.properties delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/InitialContextHelper.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java delete mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageConsumer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageConsumer.java deleted file mode 100644 index 80f965eae5..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageConsumer.java +++ /dev/null @@ -1,129 +0,0 @@ -/* 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.qpid.client.latency; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.perf.Options; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.requestreply.InitialContextHelper; - -import javax.jms.*; -import javax.naming.Context; - -/** - * - * - */ -public class MessageConsumer extends Options implements MessageListener -{ - private javax.jms.MessageProducer _producer; - private AMQConnection _connection; - private final Object _lock = new Object(); - private Session _session; - private int _receivedMessages = 0; - private long _timeFirstMessage; - private long _timeLastMessage; - private void init() - { - this.parseOptions(); - try - { - Context context = InitialContextHelper.getInitialContext(""); - ConnectionFactory factory = (ConnectionFactory) context.lookup("local"); - _connection = (AMQConnection) factory.createConnection("guest","guest"); - _session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); - Destination dest = Boolean.getBoolean("useQueue")? (Destination) context.lookup("testQueue") : - (Destination) context.lookup("testTopic"); - Destination syncQueue = (Destination) context.lookup("syncQueue"); - _producer = _session.createProducer(syncQueue); - // this should speedup the message producer - _producer.setDisableMessageTimestamp(true); - javax.jms.MessageConsumer consumer = _session.createConsumer(dest); - consumer.setMessageListener(this); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - private void run() - { - try - { - synchronized(_lock) - { - _connection.start(); - try - { - _lock.wait(); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - } - // send sync message; - _producer.send(_session.createMessage()); - System.out.println("Time to receive " + _logFrequency + " messages is: " + (_timeLastMessage - _timeFirstMessage) ); - double rate = _logFrequency / ((_timeLastMessage - _timeFirstMessage) *1.0) *1000 ; - System.out.println("The rate is " + rate + " msg/s" ); - double latency = ((_timeLastMessage - _timeFirstMessage) *1.0) / _logFrequency; - System.out.println("The latency is " + latency + " milli secs" ); - _connection.close(); - } - catch (JMSException e) - { - e.printStackTrace(); - } - } - - public void onMessage(Message message) - { - if( _receivedMessages == 0) - { - _timeFirstMessage = System.currentTimeMillis(); - } - _receivedMessages++; - if( _receivedMessages == _logFrequency) - { - _timeLastMessage = System.currentTimeMillis(); - synchronized(_lock) - { - _lock.notify(); - } - } - } - - public static void main(String[] args) - { - try - { - MessageConsumer test = new MessageConsumer(); - test.init(); - test.run(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - -} \ No newline at end of file diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java deleted file mode 100644 index c084a55bcc..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/latency/MessageProducer.java +++ /dev/null @@ -1,116 +0,0 @@ -/* 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.qpid.client.latency; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.message.TestMessageFactory; -import org.apache.qpid.client.perf.Options; -import org.apache.qpid.requestreply.InitialContextHelper; -import org.apache.qpidity.transport.network.nio.NioSender; - -import javax.jms.*; -import javax.naming.Context; - -/** - * - * - */ -public class MessageProducer extends Options -{ - private BytesMessage _payload; - private javax.jms.MessageProducer _producer; - private javax.jms.MessageConsumer _consumer; - private AMQConnection _connection; - private void init() - { - this.parseOptions(); - try - { - Context context = InitialContextHelper.getInitialContext(""); - ConnectionFactory factory = (ConnectionFactory) context.lookup("local"); - _connection = (AMQConnection) factory.createConnection("guest","guest"); - Destination dest = Boolean.getBoolean("useQueue")? (Destination) context.lookup("testQueue") : - (Destination) context.lookup("testTopic"); - Destination syncQueue = (Destination) context.lookup("syncQueue"); - _connection.start(); - Session session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); - _payload = TestMessageFactory.newBytesMessage(session, _messageSize); - _producer = session.createProducer(dest); - _consumer = session.createConsumer(syncQueue); - // this should speedup the message producer - _producer.setDisableMessageTimestamp(true); - System.out.println("Init end" ); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - private void run() - { - try - { - System.out.println("Sending " + _logFrequency + " messages"); - - // NioSender.setStartBatching(); - long startTime = System.currentTimeMillis(); - for(int i =0; i < _logFrequency; i++ ) - { - _producer.send(_payload, DeliveryMode.PERSISTENT, Message.DEFAULT_PRIORITY, 0); - } - long endProducing = System.currentTimeMillis(); - double throughput = (_logFrequency * 1000.0) / (endProducing - startTime); - System.out.println("The producer throughput is: " + throughput + " msg/s"); - - // startTime = System.currentTimeMillis(); - // NioSender.purge(); - // endProducing = System.currentTimeMillis(); - // throughput = (_logFrequency * 1000.0) / (endProducing - startTime); - // System.out.println("The NIO throughput is: " + throughput + " msg/s"); - - - // now wait for the sync message - _consumer.receive(); - // this is done - long endTime = System.currentTimeMillis(); - System.out.println("Time to send and receive " + _logFrequency + " messages is: " + (endTime - startTime) ); - double latency = ( (endTime - startTime) * 1.0) /_logFrequency; - System.out.println("The latency is " + latency + " milli secs" ); - _connection.close(); - } - catch (JMSException e) - { - e.printStackTrace(); - } - } - - public static void main(String[] args) - { - try - { - MessageProducer test = new MessageProducer(); - test.init(); - test.run(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java deleted file mode 100644 index 4d038db0a8..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * - * 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.qpid.client.message; - -import javax.jms.JMSException; -import javax.jms.Session; -import javax.jms.ObjectMessage; -import javax.jms.StreamMessage; -import javax.jms.BytesMessage; -import javax.jms.TextMessage; -import javax.jms.DeliveryMode; -import javax.jms.Destination; - -public class TestMessageFactory -{ - private static final String MESSAGE_DATA_BYTES = "-message payload-message paylaod-message payload-message paylaod"; - - public static TextMessage newTextMessage(Session session, int size) throws JMSException - { - return session.createTextMessage(createMessagePayload(size)); - } - - public static BytesMessage newBytesMessage(Session session, int size) throws JMSException - { - BytesMessage message = session.createBytesMessage(); - message.writeUTF(createMessagePayload(size)); - return message; - } - - public static StreamMessage newStreamMessage(Session session, int size) throws JMSException - { - StreamMessage message = session.createStreamMessage(); - message.writeString(createMessagePayload(size)); - return message; - } - - public static ObjectMessage newObjectMessage(Session session, int size) throws JMSException - { - if (size == 0) - { - return session.createObjectMessage(); - } - else - { - return session.createObjectMessage(createMessagePayload(size)); - } - } - - /** - * Creates an ObjectMessage with given size and sets the JMS properties - * (JMSReplyTo and DeliveryMode) - * @param session - * @param replyDestination - * @param size - * @param persistent - * @return the new ObjectMessage - * @throws JMSException - */ - public static ObjectMessage newObjectMessage(Session session, Destination replyDestination, int size, boolean persistent) throws JMSException - { - ObjectMessage msg = newObjectMessage(session, size); - - // Set the messages persistent delivery flag. - msg.setJMSDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - - // Ensure that the temporary reply queue is set as the reply to destination for the message. - if (replyDestination != null) - { - msg.setJMSReplyTo(replyDestination); - } - - return msg; - } - - public static String createMessagePayload(int size) - { - StringBuffer buf = new StringBuffer(size); - int count = 0; - while (count <= (size - MESSAGE_DATA_BYTES.length())) - { - buf.append(MESSAGE_DATA_BYTES); - count += MESSAGE_DATA_BYTES.length(); - } - if (count < size) - { - buf.append(MESSAGE_DATA_BYTES, 0, size - count); - } - - return buf.toString(); - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/ConnectionUtility.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/ConnectionUtility.java deleted file mode 100644 index 133ef5f854..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/ConnectionUtility.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.apache.qpid.client.perf; - -import javax.naming.InitialContext; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQConnectionFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ConnectionUtility -{ - private static final Logger _logger = LoggerFactory.getLogger(ConnectionUtility.class); - - private InitialContext _initialContext; - private AMQConnectionFactory _connectionFactory; - - private static ConnectionUtility _instance = new ConnectionUtility(); - - public static ConnectionUtility getInstance() - { - return _instance; - } - - private InitialContext getInitialContext() throws Exception - { - _logger.info("get InitialContext"); - if (_initialContext == null) - { - _initialContext = new InitialContext(); - } - return _initialContext; - } - - private AMQConnectionFactory getConnectionFactory() throws Exception - { - _logger.info("get ConnectionFactory"); - if (_connectionFactory == null) - { - _connectionFactory = (AMQConnectionFactory) getInitialContext().lookup("local"); - } - return _connectionFactory; - } - - public AMQConnection getConnection() throws Exception - { - _logger.info("get Connection"); - return (AMQConnection)getConnectionFactory().createConnection(); - } - -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java deleted file mode 100644 index 1124e070a1..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageConsumerTest.java +++ /dev/null @@ -1,171 +0,0 @@ -package org.apache.qpid.client.perf; - -import java.io.FileWriter; -import java.io.IOException; -import java.sql.Date; -import java.text.SimpleDateFormat; - -import javax.jms.Destination; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.Session; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQTopic; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MessageConsumerTest extends Options implements MessageListener -{ - private static final Logger _logger = LoggerFactory.getLogger(MessageConsumerTest.class); - private SimpleDateFormat df = new SimpleDateFormat("h:mm a"); - - String _logFileName; - long _startTime; - long _intervalStartTime; - long _totalMsgCount; - long _intervalCount; - - private AMQConnection _connection; - private Session _session; - - public void init() throws Exception - { - this.parseOptions(); - _logFileName = _logFilePath + "/MessageConsumerTest_" + System.currentTimeMillis(); - _connection = ConnectionUtility.getInstance().getConnection(); - _connection.start(); - Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(_connection,_destination) : new AMQTopic(_connection,_destination); - _session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); - MessageConsumer _consumer = _session.createConsumer(dest); - _consumer.setMessageListener(this); - _startTime = System.currentTimeMillis(); - if(Boolean.getBoolean("collect_stats")) - { - printHeading(); - runReaper(); - } - } - - public void onMessage(Message message) - { - try - { - /* long msgId = Integer.parseInt(message.getJMSMessageID()); - if (_verifyOrder && _totalMsgCount+1 != msgId) - { - _logger.error("Error : Message received out of order in JMSSyncConsumer:" + _id + " message id was " + msgId + " expected: " + _currentMsgCount+1); - }*/ - _totalMsgCount ++; - _intervalCount++; - if(_intervalCount >= _logFrequency) - { - _intervalCount = 0; - if (Boolean.getBoolean("collect_stats")) - { - runReaper(); - } - if (System.currentTimeMillis() - _startTime >= _expiry) - { - printSummary(); - _session.close(); - _connection.stop(); - } - } - } - catch(Exception e) - { - e.printStackTrace(); - } - } - - public void runReaper() - { - try - { - FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); - StringBuffer buf = new StringBuffer(); - Date d = new Date(System.currentTimeMillis()); - long currentTime = d.getTime(); - long intervalTime = currentTime - _intervalStartTime; - long totalTime = currentTime - _startTime; - buf.append(df.format(d)).append(","); - buf.append(d.getTime()).append(","); - buf.append(" total Msg Count: ").append(_totalMsgCount).append(","); - if(totalTime > 0 ) - buf.append(" rate: ").append(_totalMsgCount * 1000 / totalTime); - buf.append(","); - buf.append(" interval Count: ").append(_intervalCount).append(","); - if(intervalTime > 0 ) - buf.append(" interval rate: ").append(_intervalCount * 1000 / intervalTime).append(","); - buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); - buf.append("\n"); - _memoryLog.write(buf.toString()); - _memoryLog.close(); - System.out.println(buf); - _intervalStartTime = d.getTime(); - } - catch (Exception e) - { - _logger.error("Error printing info to the log file", e); - } - } - - private void printHeading() - { - try - { - FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); - String s = "Date/Time,Time (ms),total msg count,total rate (msg/sec),memory"; - _memoryLog.write(s); - _memoryLog.close(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - private void printSummary() - { - try - { - - long current = System.currentTimeMillis(); - double time = current - _startTime; - double ratio = _totalMsgCount*1000/time; - FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); - - StringBuffer buf = new StringBuffer("MessageProducerTest \n Test started at : "); - buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); - Date d = new Date(current); - buf.append(df.format(d)).append("\n Total Time taken (ms):"); - buf.append(time).append("\n Total messages sent:"); - buf.append(_totalMsgCount).append("\n producer rate:"); - buf.append(ratio).append("\n"); - _summaryLog.write(buf.toString()); - System.out.println("---------- Test Ended -------------"); - _summaryLog.close(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - - public static void main(String[] args) - { - try - { - MessageConsumerTest test = new MessageConsumerTest(); - test.init(); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java deleted file mode 100644 index 4398b28131..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/MessageProducerTest.java +++ /dev/null @@ -1,182 +0,0 @@ -package org.apache.qpid.client.perf; - -import java.io.FileWriter; -import java.io.IOException; -import java.sql.Date; -import java.text.SimpleDateFormat; - -import javax.jms.BytesMessage; -import javax.jms.Destination; -import javax.jms.MessageProducer; -import javax.jms.Session; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.message.TestMessageFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MessageProducerTest extends Options -{ - private static final Logger _logger = LoggerFactory.getLogger(MessageProducerTest.class); - private SimpleDateFormat df = new SimpleDateFormat("h:mm a"); - - String _logFileName; - long _startTime; - long _intervalStartTime; - long _totalMsgCount; - long _intervalCount; - - private AMQConnection _connection; - private Session _session; - private BytesMessage _payload; - private MessageProducer _producer; - - public void init() throws Exception - { - this.parseOptions(); - _logFileName = _logFilePath + "/MessageProducerTest_" + System.currentTimeMillis(); - _connection = ConnectionUtility.getInstance().getConnection(); - _connection.start(); - Destination dest = Boolean.getBoolean("useQueue")? new AMQQueue(_connection,_destination) : new AMQTopic(_connection,_destination); - _session = _connection.createSession(_transacted, Session.AUTO_ACKNOWLEDGE); - _payload = TestMessageFactory.newBytesMessage(_session, _messageSize); - _producer = _session.createProducer(dest); - // this should speedup the message producer - _producer.setDisableMessageTimestamp(true); - } - - public void run() - { - _startTime = System.currentTimeMillis(); - boolean run = true; - if(Boolean.getBoolean("collect_stats")) - { - printHeading(); - runReaper(); - } - - try - { - while (run) - { - _payload.setJMSMessageID(String.valueOf(_totalMsgCount+1)); - _producer.send(_payload); - _totalMsgCount ++; - _intervalCount ++; - - // check every x messages to see if times up - if(_intervalCount >= _logFrequency) - { - if (Boolean.getBoolean("collect_stats")) - { - runReaper(); - _intervalCount = 0; - } - if (System.currentTimeMillis() - _startTime >= _expiry) - { - // time to stop the test. - _session.close(); - _connection.stop(); - run = false; - } - } - } - } - catch (Exception e) - { - _logger.error("The timer thread exited", e); - } - printSummary(); - } - - public void runReaper() - { - try - { - FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); - StringBuffer buf = new StringBuffer(); - Date d = new Date(System.currentTimeMillis()); - long currentTime = d.getTime(); - long intervalTime = currentTime - _intervalStartTime; - long totalTime = currentTime - _startTime; - buf.append(df.format(d)).append(","); - buf.append(d.getTime()).append(","); - buf.append(" total Msg Count: ").append(_totalMsgCount).append(","); - if(totalTime > 0 ) - buf.append(" rate: ").append(_totalMsgCount * 1000 / totalTime); - buf.append(","); - buf.append(" interval Count: ").append(_intervalCount).append(","); - if(intervalTime > 0 ) - buf.append(" interval rate: ").append(_intervalCount * 1000 / intervalTime).append(","); - buf.append(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory()).append("\n"); - buf.append("\n"); - _memoryLog.write(buf.toString()); - _memoryLog.close(); - System.out.println(buf); - _intervalStartTime = d.getTime(); - } - catch (Exception e) - { - _logger.error("Error printing info to the log file", e); - } - } - - private void printHeading() - { - try - { - FileWriter _memoryLog = new FileWriter(_logFileName + ".csv",true); - String s = "Date/Time,Time (ms),total msg count,total rate (msg/sec),memory"; - _memoryLog.write(s); - _memoryLog.close(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - private void printSummary() - { - try - { - - long current = System.currentTimeMillis(); - double time = current - _startTime; - double ratio = _totalMsgCount*1000/time; - FileWriter _summaryLog = new FileWriter(_logFileName + "_Summary",true); - - StringBuffer buf = new StringBuffer("MessageProducerTest \n Test started at : "); - buf.append(df.format(new Date(_startTime))).append("\n Test finished at : "); - Date d = new Date(current); - buf.append(df.format(d)).append("\n Total Time taken (ms):"); - buf.append(time).append("\n Total messages sent:"); - buf.append(_totalMsgCount).append("\n producer rate:"); - buf.append(ratio).append("\n"); - _summaryLog.write(buf.toString()); - System.out.println("---------- Test Ended -------------"); - _summaryLog.close(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - - public static void main(String[] args) - { - try - { - MessageProducerTest test = new MessageProducerTest(); - test.init(); - test.run(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java deleted file mode 100644 index c0f51738db..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/perf/Options.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.apache.qpid.client.perf; - -public class Options -{ - public int _messageSize; - public boolean _transacted; - public boolean _synchronous; - public String _destination; - public long _expiry; - public long _logFrequency; - public String _logFilePath; - - /** - * System props - * -DmessageSize - * -DuseQueue - * -Dtransacted - * -Ddestinations - * -DlogFilePath - * -Duration=1H,30M,10S - * -DlogDuration=10 in mins - */ - public void parseOptions() - { - _messageSize = Integer.parseInt(System.getProperty("messageSize","100")); - _transacted = false; - _destination = System.getProperty("destination", "foo"); - _logFrequency = Long.parseLong(System.getProperty("logFrequency","10000")); - _logFilePath = System.getProperty("logFilePath"); - _expiry = getExpiry(); - - System.out.println("============= Test Data ==================="); - System.out.println("Destination : " + _destination); - System.out.println("Collect stats : " + Boolean.getBoolean("collect_stats")); - System.out.println("Log Frequency in msgs : " + _logFrequency); - System.out.println("Log file path : " + _logFilePath); - System.out.println("Test Duration : " + printTestDuration()); - System.out.println("============= /Test Data ==================="); - } - - private String printTestDuration() - { - StringBuffer buf = new StringBuffer(); - long temp = _expiry; - int hours = (int)temp/(60*60*1000); - temp = temp -hours*60*60*1000; - - int mins = (int)(temp)/(60*1000); - temp = temp -mins*60*1000; - - int secs = (int)temp/1000; - - if (hours > 0) - { - buf.append(hours).append(" hours "); - } - if (mins > 0) - { - buf.append(mins).append(" mins "); - } - if (secs > 0) - { - buf.append(secs).append(" secs"); - } - - return buf.toString(); - } - - private long getExpiry() - { - // default is 30 mins - long time = 0; - String s = System.getProperty("duration"); - if(s != null) - { - String[] temp = s.split(","); - for (String st:temp) - { - if(st.indexOf("H")>0) - { - int hour = Integer.parseInt(st.substring(0,st.indexOf("H"))); - time = time + hour * 60 * 60 * 1000; - } - else if(st.indexOf("M")>0) - { - int min = Integer.parseInt(st.substring(0,st.indexOf("M"))); - time = time + min * 60 * 1000; - } - else if(st.indexOf("S")>0) - { - int sec = Integer.parseInt(st.substring(0,st.indexOf("S"))); - time = time + sec * 1000; - } - - } - } - if (time == 0) - { - time = 30 * 60 * 1000; - } - - return time; - } - -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Client.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Client.java deleted file mode 100644 index 4a726c19ea..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Client.java +++ /dev/null @@ -1,210 +0,0 @@ -/* 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.qpid.client.topic; - -import org.apache.qpid.client.message.TestMessageFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.jms.*; -import java.util.Properties; -import java.util.Random; -import java.util.List; -import java.util.ArrayList; -import java.io.FileWriter; - -public class Client -{ - /** - * This class logger - */ - private static final Logger _logger=LoggerFactory.getLogger(Client.class); - - private long _messagesProduced=0; - private final Object _lock=new Object(); - private Message _message; - private List _runners=new ArrayList(); - - - /** - * Run the message consumer example. - * - * @param args Command line arguments. - */ - public static void main(String[] args) - { - Client syncConsumer=new Client(); - int firstArg=120; - if (args.length > 0) - { - try - { - firstArg=Integer.parseInt(args[0]); - } - catch (NumberFormatException e) - { - _logger.warn("Argument must be an integer, running for 2 minutes"); - } - } - syncConsumer.runClient(firstArg); - } - - - void runClient(long duration) - { - try - { - // Load JNDI properties - Properties properties=new Properties(); - properties.load(this.getClass().getResourceAsStream("topic.properties")); - - String logFilePath = System.getProperty("logFilePath", "./"); - FileWriter file = new FileWriter(logFilePath + "client-" + System.currentTimeMillis() + ".cvs",true); - - //Create the initial context - Context ctx=new InitialContext(properties); - - // Lookup the connection factory - ConnectionFactory conFac=(ConnectionFactory) ctx.lookup("qpidConnectionfactory"); - // create the connection - Connection connection=conFac.createConnection(); - - connection.setExceptionListener(new ExceptionListener() - { - public void onException(JMSException jmse) - { - // The connection may have broken invoke reconnect code if available. - // The connection may have broken invoke reconnect code if available. - System.err.println("Received an exception through the ExceptionListener"); - System.exit(0); - } - }); - - // Now the messageConsumer is set up we can start the connection - connection.start(); - - // Create a session on the connection - // This session is a default choice of non-transacted and uses the auto acknowledge feature of a session. - Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - Queue queueCompleted = session.createQueue("completed"); - Queue queueStarted = session.createQueue("started"); - MessageProducer prod = session.createProducer(queueCompleted); - MessageConsumer cons = session.createConsumer(queueStarted); - cons.receive(); - _logger.info("Starting producing messages"); - - _message=TestMessageFactory.newBytesMessage(session, 1024); - - Random random=new Random(); - long testDuration=0; - long totalMessagesProduced; - long messagesProducedLastInterval=0; - long intervalThroughput; - long totalThroughput; - long numProducers=1; - String info; - startNewProducer(session, random); - while (testDuration < duration) - { - // every 5 second creates a thread an print the throughput - synchronized (_lock) - { - _lock.wait(5000); - totalMessagesProduced=_messagesProduced; - } - testDuration=testDuration + 5; - intervalThroughput=(totalMessagesProduced - messagesProducedLastInterval) / 5; - totalThroughput=totalMessagesProduced / testDuration; - messagesProducedLastInterval=totalMessagesProduced; - info = "Number of producers " + numProducers + " | This interval throughput = " + - intervalThroughput + " | Total throughput = " + totalThroughput; - _logger.info(info); - file.write(info + "\n"); - startNewProducer(session, random); - numProducers++; - } - file.close(); - // stop all the producers - for (Runner runner : _runners) - { - runner.stop(); - } - _logger.info("Stopping server"); - prod.send(session.createTextMessage("stop")); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - private void startNewProducer(Session session, Random random) - throws JMSException - { - // select a random topic - int topicNumber=random.nextInt(50); - _logger.info("creating producer for topic: topic- " + topicNumber); - Topic topic=session.createTopic("topic-" + topicNumber); - MessageProducer prod=session.createProducer(topic); - Runner runner=new Runner(prod); - _runners.add(runner); - Thread thread=new Thread(runner); - thread.setDaemon(true); - thread.start(); - } - - private class Runner implements Runnable - { - MessageProducer _prod; - boolean _produce=true; - private Runner(MessageProducer prod) - { - _prod=prod; - } - - public void run() - { - while (_produce) - { - try - { - _prod.send(_message, DeliveryMode.PERSISTENT, Message.DEFAULT_PRIORITY, - Message.DEFAULT_TIME_TO_LIVE); - synchronized (_lock) - { - _messagesProduced++; - } - } - catch (Exception e) - { - e.printStackTrace(); - _produce=false; - } - } - } - - public void stop() - { - _produce=false; - } - } - -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Server.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Server.java deleted file mode 100644 index 883a7465a1..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/Server.java +++ /dev/null @@ -1,171 +0,0 @@ -/* 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.qpid.client.topic; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.naming.Context; -import javax.naming.InitialContext; - -import javax.jms.*; -import java.util.Properties; -import java.io.FileWriter; - - -public class Server -{ - /** - * This class logger - */ - private static final Logger _logger=LoggerFactory.getLogger(Server.class); - - - private final Object _lock=new Object(); - private long _numMessages=0; - public FileWriter _file; - public boolean _running=true; - - public static void main(String[] args) - { - (new Server()).runServer(); - } - - void runServer() - { - try - { - // Load JNDI properties - Properties properties=new Properties(); - properties.load(this.getClass().getResourceAsStream("topic.properties")); - - String logFilePath=System.getProperty("logFilePath", "./"); - _file=new FileWriter(logFilePath + "server-" + System.currentTimeMillis() + ".cvs", true); - - //Create the initial context - Context ctx=new InitialContext(properties); - - // Lookup the connection factory - ConnectionFactory conFac=(ConnectionFactory) ctx.lookup("qpidConnectionfactory"); - // create the connection - Connection connection=conFac.createConnection(); - - connection.setExceptionListener(new ExceptionListener() - { - public void onException(JMSException jmse) - { - // The connection may have broken invoke reconnect code if available. - // The connection may have broken invoke reconnect code if available. - _logger.warn("Received an exception through the ExceptionListener"); - System.exit(0); - } - }); - - // Create a session on the connection - // This session is a default choice of non-transacted and uses the auto acknowledge feature of a session. - // Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - for (int i=0; i < 50; i++) - { - Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic=session.createTopic("topic-" + i); - TopicSubscriber dursub=session.createDurableSubscriber(topic, "durable-" + i); - dursub.setMessageListener(new MyListener()); - } - - // Now the messageConsumer is set up we can start the connection - connection.start(); - _logger.info("Ready to consume messages"); - // listen for the termination message - Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue queueCompleted=session.createQueue("completed"); - Queue queueStarted=session.createQueue("started"); - MessageProducer prod=session.createProducer(queueStarted); - - Thread logger=new Thread(new MyLogger()); - logger.setDaemon(true); - logger.start(); - - prod.send(session.createTextMessage("start")); - long startTime=System.currentTimeMillis(); - MessageConsumer cons=session.createConsumer(queueCompleted); - cons.receive(); - - _running=false; - - long endTime=System.currentTimeMillis(); - session.close(); - _logger.info("Received " + _numMessages); - _file.write("Received " + _numMessages + "\n"); - _logger.info("Throughput " + _numMessages / (endTime - startTime) * 1000 + "msg/s"); - _file.write("Throughput " + _numMessages / (endTime - startTime) * 1000 + "msg/s"); - _file.close(); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - private class MyListener implements MessageListener - { - public void onMessage(Message message) - { - synchronized (_lock) - { - _numMessages++; - /*if(_numMessages % 1000 == 0) - { - _logger.info("received: " + _numMessages); - } */ - } - } - } - - private class MyLogger implements Runnable - { - public void run() - { - long endTime=0; - while (_running) - { - synchronized (_lock) - { - try - { - _lock.wait(5000); - if (_running) - { - endTime=endTime + 5; - String s="Throughput " + _numMessages / endTime + " msg/s"; - _logger.info(s); - _file.write(s + "\n"); - } - - } - catch (Exception e) - { - e.printStackTrace(); - } - - } - } - } - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/topic.properties b/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/topic.properties deleted file mode 100644 index cff5275e36..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/topic/topic.properties +++ /dev/null @@ -1,24 +0,0 @@ -# -# 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. -# -java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory - -connectionfactory.qpidConnectionfactory = amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672' - -# A 0.10 connection factory -#connectionfactory.qpidConnectionfactory = qpid:password=pass;username=name@tcp:localhost:5672 diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java deleted file mode 100644 index 06081e6ebf..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * - * 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.qpid.ping; - -import junit.framework.Test; -import junit.framework.TestSuite; - -import org.apache.log4j.Logger; - -import org.apache.qpid.requestreply.PingPongProducer; - -import uk.co.thebadgerset.junit.extensions.TimingController; -import uk.co.thebadgerset.junit.extensions.TimingControllerAware; - -import javax.jms.JMSException; -import javax.jms.Message; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; - -/** - * PingAsyncTestPerf is a performance test that outputs multiple timings from its test method, using the timing controller - * interface supplied by the test runner from a seperate listener thread. It differs from the {@link PingTestPerf} test - * that it extends because it can output timings as replies are received, rather than waiting until all expected replies - * are received. This is less 'blocky' than the tests in {@link PingTestPerf}, and provides a truer simulation of sending - * and recieving clients working asynchronously. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Send many ping messages and output timings asynchronously on batches received. - *
    - */ -public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerAware -{ - private static Logger _logger = Logger.getLogger(PingAsyncTestPerf.class); - - /** Holds the name of the property to get the test results logging batch size. */ - public static final String TEST_RESULTS_BATCH_SIZE_PROPNAME = "batchSize"; - - /** Holds the default test results logging batch size. */ - public static final int TEST_RESULTS_BATCH_SIZE_DEFAULT = 1000; - - /** Used to hold the timing controller passed from the test runner. */ - private TimingController _timingController; - - /** Used to generate unique correlation ids for each test run. */ - private AtomicLong corellationIdGenerator = new AtomicLong(); - - /** Holds test specifics by correlation id. This consists of the expected number of messages and the timing controler. */ - private Map perCorrelationIds = - Collections.synchronizedMap(new HashMap()); - - /** Holds the batched results listener, that does logging on batch boundaries. */ - private BatchedResultsListener batchedResultsListener = null; - - /** - * Creates a new asynchronous ping performance test with the specified name. - * - * @param name The test name. - */ - public PingAsyncTestPerf(String name) - { - super(name); - - // Sets up the test parameters with defaults. - testParameters.setPropertyIfNull(TEST_RESULTS_BATCH_SIZE_PROPNAME, - Integer.toString(TEST_RESULTS_BATCH_SIZE_DEFAULT)); - } - - /** - * Compile all the tests into a test suite. - * @return The test suite to run. Should only contain testAsyncPingOk method. - */ - public static Test suite() - { - // Build a new test suite - TestSuite suite = new TestSuite("Ping Performance Tests"); - - // Run performance tests in read committed mode. - suite.addTest(new PingAsyncTestPerf("testAsyncPingOk")); - - return suite; - } - - /** - * Accepts a timing controller from the test runner. - * - * @param timingController The timing controller to register mutliple timings with. - */ - public void setTimingController(TimingController timingController) - { - _timingController = timingController; - } - - /** - * Gets the timing controller passed in by the test runner. - * - * @return The timing controller passed in by the test runner. - */ - public TimingController getTimingController() - { - return _timingController; - } - - /** - * Sends the specified number of pings, asynchronously outputs timings on every batch boundary, and waits until - * all replies have been received or a time out occurs before exiting this method. - * - * @param numPings The number of pings to send. - * @throws Exception pass all errors out to the test harness - */ - public void testAsyncPingOk(int numPings) throws Exception - { - // _logger.debug("public void testAsyncPingOk(int numPings): called"); - - // Ensure that at least one ping was requeusted. - if (numPings == 0) - { - _logger.error("Number of pings requested was zero."); - fail("Number of pings requested was zero."); - } - - // Get the per thread test setup to run the test through. - PerThreadSetup perThreadSetup = threadSetup.get(); - PingClient pingClient = perThreadSetup._pingClient; - - // Advance the correlation id of messages to send, to make it unique for this run. - perThreadSetup._correlationId = Long.toString(corellationIdGenerator.incrementAndGet()); - // String messageCorrelationId = perThreadSetup._correlationId; - // _logger.debug("messageCorrelationId = " + messageCorrelationId); - - // Initialize the count and timing controller for the new correlation id. - PerCorrelationId perCorrelationId = new PerCorrelationId(); - TimingController tc = getTimingController().getControllerForCurrentThread(); - perCorrelationId._tc = tc; - perCorrelationId._expectedCount = pingClient.getExpectedNumPings(numPings); - perCorrelationIds.put(perThreadSetup._correlationId, perCorrelationId); - - // Send the requested number of messages, and wait until they have all been received. - long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); - int numReplies = pingClient.pingAndWaitForReply(null, numPings, timeout, perThreadSetup._correlationId); - - // Check that all the replies were received and log a fail if they were not. - if (numReplies < perCorrelationId._expectedCount) - { - perCorrelationId._tc.completeTest(false, numPings - perCorrelationId._expectedCount); - } - - // Remove the expected count and timing controller for the message correlation id, to ensure they are cleaned up. - perCorrelationIds.remove(perThreadSetup._correlationId); - } - - /** - * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. - */ - public void threadSetUp() - { - _logger.debug("public void threadSetUp(): called"); - - try - { - // Call the set up method in the super class. This creates a PingClient pinger. - super.threadSetUp(); - - // Create the chained message listener, only if it has not already been created. This is set up with the - // batch size property, to tell it what batch size to output results on. A synchronized block is used to - // ensure that only one thread creates this. - synchronized (this) - { - if (batchedResultsListener == null) - { - int batchSize = Integer.parseInt(testParameters.getProperty(TEST_RESULTS_BATCH_SIZE_PROPNAME)); - batchedResultsListener = new BatchedResultsListener(batchSize); - } - } - - // Get the set up that the super class created. - PerThreadSetup perThreadSetup = threadSetup.get(); - - // Register the chained message listener on the pinger to do its asynchronous test timings from. - perThreadSetup._pingClient.setChainedMessageListener(batchedResultsListener); - } - catch (Exception e) - { - _logger.warn("There was an exception during per thread setup.", e); - } - } - - /** - * BatchedResultsListener is a {@link PingPongProducer.ChainedMessageListener} that can be attached to the - * pinger, in order to receive notifications about every message received and the number remaining to be - * received. Whenever the number remaining crosses a batch size boundary this results listener outputs - * a test timing for the actual number of messages received in the current batch. - */ - private class BatchedResultsListener implements PingPongProducer.ChainedMessageListener - { - /** The test results logging batch size. */ - int _batchSize; - - /** - * Creates a results listener on the specified batch size. - * - * @param batchSize The batch size to use. - */ - public BatchedResultsListener(int batchSize) - { - _batchSize = batchSize; - } - - /** - * This callback method is called from all of the pingers that this test creates. It uses the correlation id - * from the message to identify the timing controller for the test thread that was responsible for sending those - * messages. - * - * @param message The message. - * @param remainingCount The count of messages remaining to be received with a particular correlation id. - * - * @throws JMSException Any underlying JMSException is allowed to fall through. - */ - public void onMessage(Message message, int remainingCount, long latency) throws JMSException - { - // Check if a batch boundary has been crossed. - if ((remainingCount % _batchSize) == 0) - { - // Extract the correlation id from the message. - String correlationId = message.getJMSCorrelationID(); - - /*_logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount - + "): called on batch boundary for message id: " + correlationId + " with thread id: " - + Thread.currentThread().getId());*/ - - // Get the details for the correlation id and check that they are not null. They can become null - // if a test times out. - PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationId); - if (perCorrelationId != null) - { - // Get the timing controller and expected count for this correlation id. - TimingController tc = perCorrelationId._tc; - int expected = perCorrelationId._expectedCount; - - // Calculate how many messages were actually received in the last batch. This will be the batch size - // except where the number expected is not a multiple of the batch size and this is the first remaining - // count to cross a batch size boundary, in which case it will be the number expected modulo the batch - // size. - int receivedInBatch = ((expected - remainingCount) < _batchSize) ? (expected % _batchSize) : _batchSize; - - // Register a test result for the correlation id. - try - { - tc.completeTest(true, receivedInBatch); - } - catch (InterruptedException e) - { - // Ignore this. It means the test runner wants to stop as soon as possible. - _logger.warn("Got InterruptedException.", e); - } - } - // Else ignore, test timed out. Should log a fail here? - } - } - } - - /** - * Holds state specific to each correlation id, needed to output test results. This consists of the count of - * the total expected number of messages, and the timing controller for the thread sending those message ids. - */ - private static class PerCorrelationId - { - public int _expectedCount; - public TimingController _tc; - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java deleted file mode 100644 index b9632eee4c..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * - * 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.qpid.ping; - -import org.apache.log4j.Logger; - -import org.apache.qpid.requestreply.PingPongProducer; - -import javax.jms.Destination; - -import java.util.List; -import java.util.Properties; - -/** - * PingClient is a {@link PingPongProducer} that does not need a {@link org.apache.qpid.requestreply.PingPongBouncer} - * to send replies to its pings. It simply listens to its own ping destinations, rather than seperate reply queues. - * It is an all in one ping client, that produces and consumes its own pings. - * - *

    The constructor increments a count of the number of ping clients created. It is assumed that where many - * are created they will all be run in parallel and be active in sending and consuming pings at the same time. - * If the unique destinations flag is not set and a pub/sub ping cycle is being run, this means that they will all hear - * pings sent by each other. The expected number of pings received will therefore be multiplied up by the number of - * active ping clients. The {@link #getConsumersPerDestination()} method is used to supply this multiplier under these - * conditions. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Create a ping producer that listens to its own pings {@link PingPongProducer} - *
    Count the number of ping producers and produce multiplier for scaling up messages expected over topic pings. - *
    - */ -public class PingClient extends PingPongProducer -{ - /** Used for debugging. */ - private final Logger log = Logger.getLogger(PingClient.class); - - /** Used to count the number of ping clients created. */ - private static int _pingClientCount; - - /** - * Creates a ping producer with the specified parameters, of which there are many. See the class level comments - * for {@link PingPongProducer} for details. This constructor creates a connection to the broker and creates - * producer and consumer sessions on it, to send and recieve its pings and replies on. - * - * @param overrides Properties containing any desired overrides to the defaults. - * - * @throws Exception Any exceptions are allowed to fall through. - */ - public PingClient(Properties overrides) throws Exception - { - super(overrides); - - _pingClientCount++; - } - - /** - * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the - * effect of making this pinger listen to its own pings. - * - * @return The ping destinations. - */ - public List getReplyDestinations() - { - return _pingDestinations; - } - - /** - * Supplies the multiplier for the number of ping clients that will hear each ping when doing pub/sub pinging. - * - * @return The scaling up of the number of expected pub/sub pings. - */ - public int getConsumersPerDestination() - { - log.debug("public int getConsumersPerDestination(): called"); - - if (_isUnique) - { - log.debug(_noOfConsumers + " consumer per destination."); - - return _noOfConsumers; - } - else - { - log.debug((_pingClientCount * _noOfConsumers) + " consumers per destination."); - - return _pingClientCount * _noOfConsumers; - } - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java deleted file mode 100644 index 2750790354..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java +++ /dev/null @@ -1,451 +0,0 @@ -/* - * - * 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.qpid.ping; - -import org.apache.log4j.Logger; - -import org.apache.qpid.requestreply.PingPongProducer; -import org.apache.qpid.util.CommandLineParser; - -import uk.co.thebadgerset.junit.extensions.util.MathUtils; -import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; - -import javax.jms.*; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * PingDurableClient is a variation of the {@link PingPongProducer} ping tool. Instead of sending its pings and - * receiving replies to them at the same time, this tool sends pings until it is signalled by some 'event' to stop - * sending. It then waits for another signal before it re-opens a fresh connection and attempts to receive all of the - * pings that it has succesfully sent. It is intended to be an interactive test that lets a user experiment with - * failure conditions when using durable messaging. - * - *

    The events that can stop it from sending are input from the user on the console, failure of its connection to - * the broker, completion of sending a specified number of messages, or expiry of a specified duration. In all cases - * it will do its best to clean up and close the connection before opening a fresh connection to receive the pings - * with. - * - *

    The event to re-connect and attempt to recieve the pings is input from the user on the console. - * - *

    This ping client inherits the configuration properties of its parent class ({@link PingPongProducer}) and - * additionally accepts the following parameters: - * - *

    - *
    Parameters
    Parameter Default Comments - *
    numMessages 100 The total number of messages to send. - *
    numMessagesToAction -1 The number of messages to send before taking a custom 'action'. - *
    duration 30S The length of time to ping for. (Format dDhHmMsS, for d days, h hours, - * m minutes and s seconds). - *
    - * - *

    This ping client also overrides some of the defaults of its parent class, to provide a reasonable set up - * when no parameters are specified. - * - *

    - *
    Parameters
    Parameter Default Comments - *
    uniqueDests false Prevents destination names being timestamped. - *
    transacted true Only makes sense to test with transactions. - *
    persistent true Only makes sense to test persistent. - *
    durableDests true Should use durable queues with persistent messages. - *
    commitBatchSize 10 - *
    rate 20 Total default test time is 5 seconds. - *
    - * - *

    When a number of messages or duration is specified, this ping client will ping until the first of those limits - * is reached. Reaching the limit will be interpreted as the first signal to stop sending, and the ping client will - * wait for the second signal before receiving its pings. - * - *

    This class provides a mechanism for extensions to add arbitrary actions, after a particular number of messages - * have been sent. When the number of messages equal the value set in the 'numMessagesToAction' property is method, - * the {@link #takeAction} method is called. By default this does nothing, but extensions of this class can provide - * custom behaviour with alternative implementations of this method (for example taking a backup). - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Send and receive pings. - *
    Accept user input to signal stop sending. - *
    Accept user input to signal start receiving. - *
    Provide feedback on pings sent versus pings received. - *
    Provide extension point for arbitrary action on a particular message count. - *
    - */ -public class PingDurableClient extends PingPongProducer implements ExceptionListener -{ - private static final Logger log = Logger.getLogger(PingDurableClient.class); - - public static final String NUM_MESSAGES_PROPNAME = "numMessages"; - public static final String NUM_MESSAGES_DEFAULT = "100"; - public static final String DURATION_PROPNAME = "duration"; - public static final String DURATION_DEFAULT = "30S"; - public static final String NUM_MESSAGES_TO_ACTION_PROPNAME = "numMessagesToAction"; - public static final String NUM_MESSAGES_TO_ACTION_DEFAULT = "-1"; - - /** The maximum length of time to wait whilst receiving pings before assuming that no more are coming. */ - private static final long TIME_OUT = 3000; - - static - { - defaults.setProperty(NUM_MESSAGES_PROPNAME, NUM_MESSAGES_DEFAULT); - defaults.setProperty(DURATION_PROPNAME, DURATION_DEFAULT); - defaults.setProperty(UNIQUE_DESTS_PROPNAME, "false"); - defaults.setProperty(TRANSACTED_PROPNAME, "true"); - defaults.setProperty(PERSISTENT_MODE_PROPNAME, "true"); - defaults.setProperty(TX_BATCH_SIZE_PROPNAME, "10"); - defaults.setProperty(RATE_PROPNAME, "20"); - defaults.setProperty(NUM_MESSAGES_TO_ACTION_PROPNAME, NUM_MESSAGES_TO_ACTION_DEFAULT); - } - - /** Specifies the number of pings to send, if larger than 0. 0 means send until told to stop. */ - private int numMessages; - - /** Holds the number of messages to send before taking triggering the action. */ - private int numMessagesToAction; - - /** Sepcifies how long to ping for, if larger than 0. 0 means send until told to stop. */ - private long duration; - - /** Used to indciate that this application should terminate. Set by the shutdown hook. */ - private boolean terminate = false; - - /** - * @throws Exception Any exceptions are allowed to fall through. - */ - public PingDurableClient(Properties overrides) throws Exception - { - super(overrides); - log.debug("public PingDurableClient(Properties overrides = " + overrides + "): called"); - - // Extract the additional configuration parameters. - ParsedProperties properties = new ParsedProperties(defaults); - properties.putAll(overrides); - - numMessages = properties.getPropertyAsInteger(NUM_MESSAGES_PROPNAME); - String durationSpec = properties.getProperty(DURATION_PROPNAME); - numMessagesToAction = properties.getPropertyAsInteger(NUM_MESSAGES_TO_ACTION_PROPNAME); - - if (durationSpec != null) - { - duration = MathUtils.parseDuration(durationSpec) * 1000000; - } - } - - /** - * Starts the ping/wait/receive process. - * - * @param args The command line arguments. - */ - public static void main(String[] args) - { - try - { - // Create a ping producer overriding its defaults with all options passed on the command line. - Properties options = - CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); - PingDurableClient pingProducer = new PingDurableClient(options); - - // Create a shutdown hook to terminate the ping-pong producer. - Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); - - // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. - // pingProducer.getConnection().setExceptionListener(pingProducer); - - // Run the test procedure. - int sent = pingProducer.send(); - pingProducer.closeConnection(); - pingProducer.waitForUser("Press return to begin receiving the pings."); - pingProducer.receive(sent); - - System.exit(0); - } - catch (Exception e) - { - System.err.println(e.getMessage()); - log.error("Top level handler caught execption.", e); - System.exit(1); - } - } - - /** - * Performs the main test procedure implemented by this ping client. See the class level comment for details. - */ - protected int send() throws Exception - { - log.debug("public void sendWaitReceive(): called"); - - log.debug("duration = " + duration); - log.debug("numMessages = " + numMessages); - - if (duration > 0) - { - System.out.println("Sending for up to " + (duration / 1000000000f) + " seconds."); - } - - if (_rate > 0) - { - System.out.println("Sending at " + _rate + " messages per second."); - } - - if (numMessages > 0) - { - System.out.println("Sending up to " + numMessages + " messages."); - } - - // Establish the connection and the message producer. - establishConnection(true, false); - _connection.start(); - - Message message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent); - - // Send pings until a terminating condition is received. - boolean endCondition = false; - int messagesSent = 0; - int messagesCommitted = 0; - int messagesNotCommitted = 0; - long start = System.nanoTime(); - - // Clear console in. - clearConsole(); - - while (!endCondition) - { - boolean committed = false; - - try - { - committed = sendMessage(messagesSent, message) && _transacted; - - messagesSent++; - messagesNotCommitted++; - - // Keep count of the number of messsages currently committed and pending commit. - if (committed) - { - log.debug("Adding " + messagesNotCommitted + " messages to the committed count."); - messagesCommitted += messagesNotCommitted; - messagesNotCommitted = 0; - - System.out.println("Commited: " + messagesCommitted); - } - } - catch (JMSException e) - { - log.debug("Got JMSException whilst sending."); - _publish = false; - } - - // Perform the arbitrary action if the number of messages sent has reached the right number. - if (messagesSent == numMessagesToAction) - { - System.out.println("At action point, Messages sent = " + messagesSent + ", Messages Committed = " - + messagesCommitted + ", Messages not Committed = " + messagesNotCommitted); - takeAction(); - } - - // Determine if the end condition has been met, based on the number of messages, time passed, errors on - // the connection or user input. - long now = System.nanoTime(); - - if ((duration != 0) && ((now - start) > duration)) - { - System.out.println("Send halted because duration expired."); - endCondition = true; - } - else if ((numMessages != 0) && (messagesSent >= numMessages)) - { - System.out.println("Send halted because # messages completed."); - endCondition = true; - } - else if (System.in.available() > 0) - { - System.out.println("Send halted by user input."); - endCondition = true; - - clearConsole(); - } - else if (!_publish) - { - System.out.println("Send halted by error on the connection."); - endCondition = true; - } - } - - log.debug("messagesSent = " + messagesSent); - log.debug("messagesCommitted = " + messagesCommitted); - log.debug("messagesNotCommitted = " + messagesNotCommitted); - - System.out.println("Messages sent: " + messagesSent + ", Messages Committed = " + messagesCommitted - + ", Messages not Committed = " + messagesNotCommitted); - - return messagesSent; - } - - protected void closeConnection() - { - // Clean up the connection. - try - { - close(); - } - catch (JMSException e) - { - log.debug("There was an error whilst closing the connection: " + e, e); - System.out.println("There was an error whilst closing the connection."); - - // Ignore as did best could manage to clean up. - } - } - - protected void receive(int messagesSent) throws Exception - { - // Re-establish the connection and the message consumer. - _queueJVMSequenceID = new AtomicInteger(); - _queueSharedID = new AtomicInteger(); - - establishConnection(false, true); - _consumer[0].setMessageListener(null); - _consumerConnection[0].start(); - - // Try to receive all of the pings that were successfully sent. - int messagesReceived = 0; - boolean endCondition = false; - - while (!endCondition) - { - // Message received = _consumer.receiveNoWait(); - Message received = _consumer[0].receive(TIME_OUT); - log.debug("received = " + received); - - if (received != null) - { - messagesReceived++; - } - - // Determine if the end condition has been met, based on the number of messages and time passed since last - // receiving a message. - if (received == null) - { - System.out.println("Timed out."); - endCondition = true; - } - else if (messagesReceived >= messagesSent) - { - System.out.println("Got all messages."); - endCondition = true; - } - } - - // Ensure messages received are committed. - if (_consTransacted) - { - try - { - _consumerSession[0].commit(); - System.out.println("Committed for all messages received."); - } - catch (JMSException e) - { - log.debug("Error during commit: " + e, e); - System.out.println("Error during commit."); - try - { - _consumerSession[0].rollback(); - System.out.println("Rolled back on all messages received."); - } - catch (JMSException e2) - { - log.debug("Error during rollback: " + e, e); - System.out.println("Error on roll back of all messages received."); - } - - } - } - - log.debug("messagesReceived = " + messagesReceived); - - System.out.println("Messages received: " + messagesReceived); - - // Clean up the connection. - close(); - } - - /** - * Clears any pending input from the console. - */ - private void clearConsole() - { - try - { - BufferedReader bis = new BufferedReader(new InputStreamReader(System.in)); - - // System.in.skip(System.in.available()); - while (bis.ready()) - { - bis.readLine(); - } - } - catch (IOException e) - { } - } - - /** - * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the - * effect of making this pinger listen to its own pings. - * - * @return The ping destinations. - */ - public List getReplyDestinations() - { - return _pingDestinations; - } - - /** - * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered with - * the runtime system as a shutdown hook. This shutdown hook sets an additional terminate flag, compared with the - * shutdown hook in {@link PingPongProducer}, because the publish flag is used to indicate that sending or receiving - * message should stop, not that the application should termiante. - * - * @return A shutdown hook for the ping loop. - */ - public Thread getShutdownHook() - { - return new Thread(new Runnable() - { - public void run() - { - stop(); - terminate = true; - } - }); - } - - /** - * Performs an aribtrary action once the 'numMesagesToAction' count is reached on sending messages. This default - * implementation does nothing. - */ - public void takeAction() - { } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java deleted file mode 100644 index 55414664da..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * - * 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.qpid.ping; - -import junit.framework.Test; -import junit.framework.TestSuite; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.message.AMQMessage; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.requestreply.PingPongProducer; - -import uk.co.thebadgerset.junit.extensions.TimingController; -import uk.co.thebadgerset.junit.extensions.TimingControllerAware; -import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; - -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.ObjectMessage; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; - -/** - * PingLatencyTestPerf is a performance test that outputs multiple timings from its test method, using the timing - * controller interface supplied by the test runner from a seperate listener thread. It outputs round trip timings for - * individual ping messages rather than for how long a complete batch of messages took to process. It also differs from - * the {@link PingTestPerf} test that it extends because it can output timings as replies are received, rather than - * waiting until all expected replies are received. - * - *

    This test does not output timings for every single ping message, as when running at high volume, writing the test - * log for a vast number of messages would slow the testing down. Instead samples ping latency occasionally. The - * frequency of ping sampling is set using the {@link #TEST_RESULTS_BATCH_SIZE_PROPNAME} property, to override the - * default of every {@link #DEFAULT_TEST_RESULTS_BATCH_SIZE}. - * - *

    The size parameter logged for each individual ping is set to the size of the batch of messages that the - * individual timed ping was taken from, rather than 1 for a single message. This is so that the total throughput - * (messages / time) can be calculated in order to examine the relationship between throughput and latency. - * - *

    CRC Card
    Responsibilities Collaborations
    Send many ping - * messages and output timings for sampled individual pings.
    - */ -public class PingLatencyTestPerf extends PingTestPerf implements TimingControllerAware -{ - private static Logger _logger = Logger.getLogger(PingLatencyTestPerf.class); - - /** Holds the name of the property to get the test results logging batch size. */ - public static final String TEST_RESULTS_BATCH_SIZE_PROPNAME = "batchSize"; - - /** Holds the default test results logging batch size. */ - public static final int DEFAULT_TEST_RESULTS_BATCH_SIZE = 1000; - - /** Used to hold the timing controller passed from the test runner. */ - private TimingController _timingController; - - /** Used to generate unique correlation ids for each test run. */ - private AtomicLong corellationIdGenerator = new AtomicLong(); - - /** - * Holds test specifics by correlation id. This consists of the expected number of messages and the timing - * controler. - */ - private Map perCorrelationIds = - Collections.synchronizedMap(new HashMap()); - - /** Holds the batched results listener, that does logging on batch boundaries. */ - private BatchedResultsListener batchedResultsListener = null; - - /** - * Creates a new asynchronous ping performance test with the specified name. - * - * @param name The test name. - */ - public PingLatencyTestPerf(String name) - { - super(name); - - // Sets up the test parameters with defaults. - ParsedProperties.setSysPropertyIfNull(TEST_RESULTS_BATCH_SIZE_PROPNAME, - Integer.toString(DEFAULT_TEST_RESULTS_BATCH_SIZE)); - } - - /** Compile all the tests into a test suite. */ - public static Test suite() - { - // Build a new test suite - TestSuite suite = new TestSuite("Ping Latency Tests"); - - // Run performance tests in read committed mode. - suite.addTest(new PingLatencyTestPerf("testPingLatency")); - - return suite; - } - - /** - * Accepts a timing controller from the test runner. - * - * @param timingController The timing controller to register mutliple timings with. - */ - public void setTimingController(TimingController timingController) - { - _timingController = timingController; - } - - /** - * Gets the timing controller passed in by the test runner. - * - * @return The timing controller passed in by the test runner. - */ - public TimingController getTimingController() - { - return _timingController; - } - - /** - * Sends the specified number of pings, asynchronously outputs timings on every batch boundary, and waits until all - * replies have been received or a time out occurs before exiting this method. - * - * @param numPings The number of pings to send. - */ - public void testPingLatency(int numPings) throws Exception - { - _logger.debug("public void testPingLatency(int numPings): called"); - - // Ensure that at least one ping was requeusted. - if (numPings == 0) - { - _logger.error("Number of pings requested was zero."); - } - - // Get the per thread test setup to run the test through. - PerThreadSetup perThreadSetup = threadSetup.get(); - PingClient pingClient = perThreadSetup._pingClient; - - // Advance the correlation id of messages to send, to make it unique for this run. - String messageCorrelationId = Long.toString(corellationIdGenerator.incrementAndGet()); - _logger.debug("messageCorrelationId = " + messageCorrelationId); - - // Initialize the count and timing controller for the new correlation id. - PerCorrelationId perCorrelationId = new PerCorrelationId(); - TimingController tc = getTimingController().getControllerForCurrentThread(); - perCorrelationId._tc = tc; - perCorrelationId._expectedCount = numPings; - perCorrelationIds.put(messageCorrelationId, perCorrelationId); - - // Attach the chained message listener to the ping producer to listen asynchronously for the replies to these - // messages. - pingClient.setChainedMessageListener(batchedResultsListener); - - // Generate a sample message of the specified size. - Message msg = - pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0), - testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), - testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); - - // Send the requested number of messages, and wait until they have all been received. - long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); - int numReplies = pingClient.pingAndWaitForReply(msg, numPings, timeout, null); - - // Check that all the replies were received and log a fail if they were not. - if (numReplies < numPings) - { - tc.completeTest(false, 0); - } - - // Remove the chained message listener from the ping producer. - pingClient.removeChainedMessageListener(); - - // Remove the expected count and timing controller for the message correlation id, to ensure they are cleaned up. - perCorrelationIds.remove(messageCorrelationId); - } - - /** Performs test fixture creation on a per thread basis. This will only be called once for each test thread. */ - public void threadSetUp() - { - _logger.debug("public void threadSetUp(): called"); - - try - { - // Call the set up method in the super class. This creates a PingClient pinger. - super.threadSetUp(); - - // Create the chained message listener, only if it has not already been created. This is set up with the - // batch size property, to tell it what batch size to output results on. A synchronized block is used to - // ensure that only one thread creates this. - synchronized (this) - { - if (batchedResultsListener == null) - { - int batchSize = Integer.parseInt(testParameters.getProperty(TEST_RESULTS_BATCH_SIZE_PROPNAME)); - batchedResultsListener = new BatchedResultsListener(batchSize); - } - } - - // Get the set up that the super class created. - PerThreadSetup perThreadSetup = threadSetup.get(); - - // Register the chained message listener on the pinger to do its asynchronous test timings from. - perThreadSetup._pingClient.setChainedMessageListener(batchedResultsListener); - } - catch (Exception e) - { - _logger.warn("There was an exception during per thread setup.", e); - } - } - - /** - * BatchedResultsListener is a {@link org.apache.qpid.requestreply.PingPongProducer.ChainedMessageListener} that can - * be attached to the pinger, in order to receive notifications about every message received and the number - * remaining to be received. Whenever the number remaining crosses a batch size boundary this results listener - * outputs a test timing for the actual number of messages received in the current batch. - */ - private class BatchedResultsListener implements PingPongProducer.ChainedMessageListener - { - /** The test results logging batch size. */ - int _batchSize; - private boolean _strictAMQP; - - /** - * Creates a results listener on the specified batch size. - * - * @param batchSize The batch size to use. - */ - public BatchedResultsListener(int batchSize) - { - _batchSize = batchSize; - _strictAMQP = - Boolean.parseBoolean(System.getProperties().getProperty(AMQSession.STRICT_AMQP, - AMQSession.STRICT_AMQP_DEFAULT)); - } - - /** - * This callback method is called from all of the pingers that this test creates. It uses the correlation id - * from the message to identify the timing controller for the test thread that was responsible for sending those - * messages. - * - * @param message The message. - * @param remainingCount The count of messages remaining to be received with a particular correlation id. - * - * @throws javax.jms.JMSException Any underlying JMSException is allowed to fall through. - */ - public void onMessage(Message message, int remainingCount, long latency) throws JMSException - { - _logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount + "): called"); - - // Check if a batch boundary has been crossed. - if ((remainingCount % _batchSize) == 0) - { - // Extract the correlation id from the message. - String correlationId = message.getJMSCorrelationID(); - - // Get the details for the correlation id and check that they are not null. They can become null - // if a test times out. - PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationId); - if (perCorrelationId != null) - { - // Get the timing controller and expected count for this correlation id. - TimingController tc = perCorrelationId._tc; - int expected = perCorrelationId._expectedCount; - - // Calculate how many messages were actually received in the last batch. This will be the batch size - // except where the number expected is not a multiple of the batch size and this is the first remaining - // count to cross a batch size boundary, in which case it will be the number expected modulo the batch - // size. - int receivedInBatch = ((expected - remainingCount) < _batchSize) ? (expected % _batchSize) : _batchSize; - - // Register a test result for the correlation id. - try - { - tc.completeTest(true, receivedInBatch, latency); - } - catch (InterruptedException e) - { - // Ignore this. It means the test runner wants to stop as soon as possible. - _logger.warn("Got InterruptedException.", e); - } - } - // Else ignore, test timed out. Should log a fail here? - } - } - } - - /** - * Holds state specific to each correlation id, needed to output test results. This consists of the count of the - * total expected number of messages, and the timing controller for the thread sending those message ids. - */ - private static class PerCorrelationId - { - public int _expectedCount; - public TimingController _tc; - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java deleted file mode 100644 index 150f7c0d52..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * - * 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.qpid.ping; - -import java.util.Properties; - -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.message.TestMessageFactory; -import org.apache.qpid.util.CommandLineParser; - -/** - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    - */ -public class PingSendOnlyClient extends PingDurableClient -{ - private static final Logger log = Logger.getLogger(PingSendOnlyClient.class); - - public PingSendOnlyClient(Properties overrides) throws Exception - { - super(overrides); - } - - /** - * Starts the ping/wait/receive process. - * - * @param args The command line arguments. - */ - public static void main(String[] args) - { - try - { - // Create a ping producer overriding its defaults with all options passed on the command line. - Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); - PingSendOnlyClient pingProducer = new PingSendOnlyClient(options); - - // Create a shutdown hook to terminate the ping-pong producer. - Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); - - // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. - // pingProducer.getConnection().setExceptionListener(pingProducer); - - // Run the test procedure. - int sent = pingProducer.send(); - pingProducer.waitForUser("Press return to close connection and quit."); - pingProducer.closeConnection(); - - System.exit(0); - } - catch (Exception e) - { - System.err.println(e.getMessage()); - log.error("Top level handler caught execption.", e); - System.exit(1); - } - } - - public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException - { - Message msg = TestMessageFactory.newTextMessage(_producerSession, messageSize); - - // Timestamp the message in nanoseconds. - msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); - - return msg; - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java deleted file mode 100644 index 375007584b..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * - * 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.qpid.ping; - -import junit.framework.Assert; -import junit.framework.Test; -import junit.framework.TestSuite; - -import org.apache.log4j.Logger; - -import org.apache.qpid.requestreply.PingPongProducer; - -import uk.co.thebadgerset.junit.extensions.AsymptoticTestCase; -import uk.co.thebadgerset.junit.extensions.TestThreadAware; -import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; -import uk.co.thebadgerset.junit.extensions.util.TestContextProperties; - -import javax.jms.*; - -/** - * PingTestPerf is a ping test, that has been written with the intention of being scaled up to run many times - * simultaneously to simluate many clients/producers/connections. - * - *

    A single run of the test using the default JUnit test runner will result in the sending and timing of a single - * full round trip ping. This test may be scaled up using a suitable JUnit test runner. - * - *

    The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a - * temporary queue for replies. This setup is only established once for all the test repeats/threads that may be run, - * except if the connection is lost in which case an attempt to re-establish the setup is made. - * - *

    The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that - * is the name of the temporary queue, fires off a message on the original queue and waits for a response on the - * temporary queue. - * - *

    Configurable test properties: message size, transacted or not, persistent or not. Broker connection details. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    - */ -public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware -{ - private static Logger _logger = Logger.getLogger(PingTestPerf.class); - - /** Thread local to hold the per-thread test setup fields. */ - ThreadLocal threadSetup = new ThreadLocal(); - - /** Holds a property reader to extract the test parameters from. */ - protected ParsedProperties testParameters = - TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/); - - public PingTestPerf(String name) - { - super(name); - - _logger.debug("testParameters = " + testParameters); - } - - /** - * Compile all the tests into a test suite. - * @return The test method testPingOk. - */ - public static Test suite() - { - // Build a new test suite - TestSuite suite = new TestSuite("Ping Performance Tests"); - - // Run performance tests in read committed mode. - suite.addTest(new PingTestPerf("testPingOk")); - - return suite; - } - - public void testPingOk(int numPings) throws Exception - { - if (numPings == 0) - { - Assert.fail("Number of pings requested was zero."); - } - - // Get the per thread test setup to run the test through. - PerThreadSetup perThreadSetup = threadSetup.get(); - - if (perThreadSetup == null) - { - Assert.fail("Could not get per thread test setup, it was null."); - } - - // Generate a sample message. This message is already time stamped and has its reply-to destination set. - Message msg = - perThreadSetup._pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0), - testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), - testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); - - // start the test - long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); - int numReplies = perThreadSetup._pingClient.pingAndWaitForReply(msg, numPings, timeout, null); - - // Fail the test if the timeout was exceeded. - if (numReplies != perThreadSetup._pingClient.getExpectedNumPings(numPings)) - { - Assert.fail("The ping timed out after " + timeout + " ms. Messages Sent = " + numPings + ", MessagesReceived = " - + numReplies); - } - } - - /** - * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. - */ - public void threadSetUp() - { - _logger.debug("public void threadSetUp(): called"); - - try - { - PerThreadSetup perThreadSetup = new PerThreadSetup(); - - // This is synchronized because there is a race condition, which causes one connection to sleep if - // all threads try to create connection concurrently. - synchronized (this) - { - // Establish a client to ping a Destination and listen the reply back from same Destination - perThreadSetup._pingClient = new PingClient(testParameters); - perThreadSetup._pingClient.establishConnection(true, true); - } - // Start the client connection - perThreadSetup._pingClient.start(); - - // Attach the per-thread set to the thread. - threadSetup.set(perThreadSetup); - } - catch (Exception e) - { - _logger.warn("There was an exception during per thread setup.", e); - } - } - - /** - * Performs test fixture clean - */ - public void threadTearDown() - { - _logger.debug("public void threadTearDown(): called"); - - try - { - // Get the per thread test fixture. - PerThreadSetup perThreadSetup = threadSetup.get(); - - // Close the pingers so that it cleans up its connection cleanly. - synchronized (this) - { - if ((perThreadSetup != null) && (perThreadSetup._pingClient != null)) - { - perThreadSetup._pingClient.close(); - } - } - } - catch (JMSException e) - { - _logger.warn("There was an exception during per thread tear down."); - } - finally - { - // Ensure the per thread fixture is reclaimed. - threadSetup.remove(); - } - } - - protected static class PerThreadSetup - { - /** - * Holds the test ping client. - */ - protected PingClient _pingClient; - protected String _correlationId; - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/InitialContextHelper.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/InitialContextHelper.java deleted file mode 100644 index b684fd6b9b..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/InitialContextHelper.java +++ /dev/null @@ -1,55 +0,0 @@ -/* 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.qpid.requestreply; - -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.NamingException; -import java.util.Properties; -import java.io.InputStream; -import java.io.IOException; - -/** - * - * - */ -public class InitialContextHelper -{ - - public static Context getInitialContext(String propertyFile) throws IOException, NamingException - { - if ((propertyFile == null) || (propertyFile.length() == 0)) - { - propertyFile = "/perftests.properties"; - } - - Properties fileProperties = new Properties(); - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - // NB: Need to change path to reflect package if moving classes around ! - InputStream is = cl.getResourceAsStream(propertyFile); - if( is != null ) - { - fileProperties.load(is); - return new InitialContext(fileProperties); - } - else - { - return new InitialContext(); - } - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java deleted file mode 100644 index 8bcbdbd369..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java +++ /dev/null @@ -1,392 +0,0 @@ -/* - * - * 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.qpid.requestreply; - -import java.io.IOException; -import java.net.InetAddress; -import java.text.SimpleDateFormat; -import java.util.Date; - -import javax.jms.*; -import javax.naming.Context; - -import org.apache.log4j.Logger; - -/** - * PingPongBouncer is a message listener the bounces back messages to their reply to destination. This is used to return - * ping messages generated by {@link org.apache.qpid.requestreply.PingPongProducer} but could be used for other purposes - * too. - *

    - *

    The correlation id from the received message is extracted, and placed into the reply as the correlation id. Messages - * are bounced back to their reply-to destination. The original sender of the message has the option to use either a unique - * temporary queue or the correlation id to correlate the original message to the reply. - *

    - *

    There is a verbose mode flag which causes information about each ping to be output to the console - * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should - * be disabled for real timing tests as writing to the console will slow things down. - *

    - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Bounce back messages to their reply to destination. - *
    Provide command line invocation to start the bounce back on a configurable broker url. - *
    - * - * @todo Replace the command line parsing with a neater tool. - * @todo Make verbose accept a number of messages, only prints to console every X messages. - */ -public class PingPongBouncer implements MessageListener -{ - private static final Logger _logger = Logger.getLogger(PingPongBouncer.class); - - /** - * The default prefetch size for the message consumer. - */ - private static final int PREFETCH = 1; - - /** - * The default no local flag for the message consumer. - */ - private static final boolean NO_LOCAL = true; - - private static final String DEFAULT_DESTINATION_NAME = "ping"; - - /** - * The default exclusive flag for the message consumer. - */ - private static final boolean EXCLUSIVE = false; - - /** - * A convenient formatter to use when time stamping output. - */ - protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); - - /** - * Used to indicate that the reply generator should log timing info to the console (logger info level). - */ - private boolean _verbose = false; - - /** - * Determines whether this bounce back client bounces back messages persistently. - */ - private boolean _persistent = false; - - private Destination _consumerDestination; - - /** - * Keeps track of the response destination of the previous message for the last reply to producer cache. - */ - private Destination _lastResponseDest; - - /** - * The producer for sending replies with. - */ - private MessageProducer _replyProducer; - - /** - * The consumer controlSession. - */ - private Session _consumerSession; - - /** - * The producer controlSession. - */ - private Session _producerSession; - - /** - * Holds the connection to the broker. - */ - private Connection _connection; - - /** - * Flag used to indicate if this is a point to point or pub/sub ping client. - */ - private boolean _isPubSub = false; - - /** - * This flag is used to indicate that the user should be prompted to kill a broker, in order to test - * failover, immediately before committing a transaction. - */ - protected boolean _failBeforeCommit = false; - - /** - * This flag is used to indicate that the user should be prompted to a kill a broker, in order to test - * failover, immediate after committing a transaction. - */ - protected boolean _failAfterCommit = false; - - /** - * Creates a PingPongBouncer on the specified producer and consumer sessions. - * - * @param fileProperties The path to the file properties - * @param factoryName The factory name - * @param username The broker username. - * @param password The broker password. - * @param destinationName The name of the queue to receive pings on - * (or root of the queue name where many queues are generated). - * @param persistent A flag to indicate that persistent message should be used. - * @param transacted A flag to indicate that pings should be sent within transactions. - * @param selector A message selector to filter received pings with. - * @param verbose A flag to indicate that message timings should be sent to the console. - * @throws Exception All underlying exceptions allowed to fall through. This is only test code... - */ - public PingPongBouncer(String fileProperties, String factoryName, String username, String password, - String destinationName, boolean persistent, boolean transacted, - String selector, boolean verbose, boolean pubsub) throws Exception - { - // Create a client id to uniquely identify this client. - InetAddress address = InetAddress.getLocalHost(); - String clientId = address.getHostName() + System.currentTimeMillis(); - _verbose = verbose; - _persistent = persistent; - setPubSub(pubsub); - // Connect to the broker. - Context context = InitialContextHelper.getInitialContext(fileProperties); - ConnectionFactory factory = (ConnectionFactory) context.lookup(factoryName); - setConnection(factory.createConnection(username, password)); - - // Create a controlSession to listen for messages on and one to send replies on, transactional depending on the - // command line option. - _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); - _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); - - // Create the queue to listen for message on. - createConsumerDestination(destinationName); - MessageConsumer consumer = _consumerSession.createConsumer(_consumerDestination, selector, NO_LOCAL); - - // Create a producer for the replies, without a default destination. - _replyProducer = _producerSession.createProducer(null); - _replyProducer.setDisableMessageTimestamp(true); - _replyProducer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - - // Set this up to listen for messages on the queue. - consumer.setMessageListener(this); - } - - private static void usage() - { - System.err.println( - "Usage: PingPongBouncer \n" + "-host : broker host\n" + "-port : broker port\n" + "-destinationname : queue/topic name\n" + "-transacted : (true/false). Default is false\n" + "-persistent : (true/false). Default is false\n" + "-pubsub : (true/false). Default is false\n" + "-selector : selector string\n"); - } - - /** - * This is a callback method that is notified of all messages for which this has been registered as a message - * listener on a message consumer. It sends a reply (pong) to all messages it receieves on the reply to - * destination of the message. - * - * @param message The message that triggered this callback. - */ - public void onMessage(Message message) - { - try - { - String messageCorrelationId = message.getJMSCorrelationID(); - if (_verbose) - { - _logger.info(timestampFormatter - .format(new Date()) + ": Got ping with correlation id, " + messageCorrelationId); - } - - // Get the reply to destination from the message and check it is set. - Destination responseDest = message.getJMSReplyTo(); - - if (responseDest == null) - { - _logger.debug("Cannot send reply because reply-to destination is null."); - - return; - } - - // Spew out some timing information if verbose mode is on. - if (_verbose) - { - Long timestamp = message.getLongProperty("timestamp"); - - if (timestamp != null) - { - long diff = System.currentTimeMillis() - timestamp; - _logger.info("Time to bounce point: " + diff); - } - } - - // Correlate the reply to the original. - message.setJMSCorrelationID(messageCorrelationId); - - // Send the receieved message as the pong reply. - _replyProducer.send(responseDest, message); - - if (_verbose) - { - _logger.info(timestampFormatter - .format(new Date()) + ": Sent reply with correlation id, " + messageCorrelationId); - } - - // Commit the transaction if running in transactional mode. - commitTx(_producerSession); - } - catch (JMSException e) - { - _logger.debug("There was a JMSException: " + e.getMessage(), e); - } - } - - /** - * Gets the underlying connection that this ping client is running on. - * - * @return The underlying connection that this ping client is running on. - */ - public Connection getConnection() - { - return _connection; - } - - /** - * Sets the connection that this ping client is using. - * - * @param connection The ping connection. - */ - public void setConnection(Connection connection) - { - this._connection = connection; - } - - /** - * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic. - * - * @param pubsub true if this client is pinging a topic, false if it is pinging a queue. - */ - public void setPubSub(boolean pubsub) - { - _isPubSub = pubsub; - } - - /** - * Checks whether this client is a p2p or pub/sub ping client. - * - * @return true if this client is pinging a topic, false if it is pinging a queue. - */ - public boolean isPubSub() - { - return _isPubSub; - } - - /** - * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not - * a transactional controlSession, this method does nothing. - *

    - *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the - * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker - * after the commit is applied. - * - * @throws javax.jms.JMSException If the commit fails and then the rollback fails. - */ - protected void commitTx(Session session) throws JMSException - { - if (session.getTransacted()) - { - try - { - if (_failBeforeCommit) - { - _logger.trace("Failing Before Commit"); - doFailover(); - } - - session.commit(); - - if (_failAfterCommit) - { - _logger.trace("Failing After Commit"); - doFailover(); - } - - _logger.trace("Session Commited."); - } - catch (JMSException e) - { - _logger.trace("JMSException on commit:" + e.getMessage(), e); - - try - { - session.rollback(); - _logger.debug("Message rolled back."); - } - catch (JMSException jmse) - { - _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); - - // Both commit and rollback failed. Throw the rollback exception. - throw jmse; - } - } - } - } - - /** - * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block - * until the user supplied some input on the terminal. - * - * @param broker The name of the broker to terminate. - */ - protected void doFailover(String broker) - { - System.out.println("Kill Broker " + broker + " now."); - try - { - System.in.read(); - } - catch (IOException e) - { - } - - System.out.println("Continuing."); - } - - /** - * Prompts the user to terminate the broker, in order to test failover functionality. This method will block - * until the user supplied some input on the terminal. - */ - protected void doFailover() - { - System.out.println("Kill Broker now."); - try - { - System.in.read(); - } - catch (IOException e) - { - } - - System.out.println("Continuing."); - - } - - private void createConsumerDestination(String name) throws JMSException - { - if (isPubSub()) - { - _consumerDestination = _consumerSession.createTopic(name); - } - else - { - _consumerDestination = _consumerSession.createQueue(name); - } - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java deleted file mode 100644 index da6d6eb7d0..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ /dev/null @@ -1,1717 +0,0 @@ -/* - * - * 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.qpid.requestreply; - -import org.apache.log4j.Logger; -import org.apache.log4j.NDC; - -import org.apache.qpid.test.framework.TestUtils; - -import uk.co.thebadgerset.junit.extensions.BatchedThrottle; -import uk.co.thebadgerset.junit.extensions.Throttle; -import uk.co.thebadgerset.junit.extensions.util.CommandLineParser; -import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; - -import javax.jms.*; -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.NamingException; - -import java.io.*; -import java.net.InetAddress; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -/** - * PingPongProducer is a client that sends test messages, and waits for replies to these messages. The replies may - * either be generated by another client (see {@link PingPongBouncer}, or an extension of it may be used that listens - * to its own messages and does not send replies (see {@link org.apache.qpid.ping.PingClient}). The intention of ping - * pong producer is that it is a swiss-army knife test client that makes almost every aspect of its behaviour - * configurable. - * - *

    The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. This - * means that this class has to do some work to correlate pings with pongs; it expectes the original message correlation - * id in the ping to be bounced back in the reply correlation id. - * - *

    This ping tool accepts a vast number of configuration options, all of which are passed in to the constructor. It - * can ping topics or queues; ping multiple destinations; do persistent pings; send messages of any size; do pings within - * transactions; control the number of pings to send in each transaction; limit its sending rate; and perform failover - * testing. A complete list of accepted parameters, default values and comments on their usage is provided here: - * - *

    - *
    Parameters
    Parameter Default Comments - *
    messageSize 0 Message size in bytes. Not including any headers. - *
    destinationName ping The root name to use to generate destination names to ping. - *
    persistent false Determines whether peristent delivery is used. - *
    transacted false Determines whether messages are sent/received in transactions. - *
    broker tcp://localhost:5672 Determines the broker to connect to. - *
    virtualHost test Determines the virtual host to send all ping over. - *
    rate 0 The maximum rate (in hertz) to send messages at. 0 means no limit. - *
    verbose false The verbose flag for debugging. Prints to console on every message. - *
    pubsub false Whether to ping topics or queues. Uses p2p by default. - *
    failAfterCommit false Whether to prompt user to kill broker after a commit batch. - *
    failBeforeCommit false Whether to prompt user to kill broker before a commit batch. - *
    failAfterSend false Whether to prompt user to kill broker after a send. - *
    failBeforeSend false Whether to prompt user to kill broker before a send. - *
    failOnce true Whether to prompt for failover only once. - *
    username guest The username to access the broker with. - *
    password guest The password to access the broker with. - *
    selector null Not used. Defines a message selector to filter pings with. - *
    destinationCount 1 The number of destinations to send pings to. - *
    numConsumers 1 The number of consumers on each destination. - *
    timeout 30000 In milliseconds. The timeout to stop waiting for replies. - *
    commitBatchSize 1 The number of messages per transaction in transactional mode. - *
    uniqueDests true Whether each receivers only listens to one ping destination or all. - *
    durableDests false Whether or not durable destinations are used. - *
    ackMode AUTO_ACK The message acknowledgement mode. Possible values are: - * 0 - SESSION_TRANSACTED - * 1 - AUTO_ACKNOWLEDGE - * 2 - CLIENT_ACKNOWLEDGE - * 3 - DUPS_OK_ACKNOWLEDGE - * 257 - NO_ACKNOWLEDGE - * 258 - PRE_ACKNOWLEDGE - *
    consTransacted false Whether or not consumers use transactions. Defaults to the same value - * as the 'transacted' option if not seperately defined. - *
    consAckMode AUTO_ACK The message acknowledgement mode for consumers. Defaults to the same - * value as 'ackMode' if not seperately defined. - *
    maxPending 0 The maximum size in bytes, of messages sent but not yet received. - * Limits the volume of messages currently buffered on the client - * or broker. Can help scale test clients by limiting amount of buffered - * data to avoid out of memory errors. - *
    - * - *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop - * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so by - * starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is also - * registered to terminate the ping-pong loop cleanly. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Provide a ping and wait for all responses cycle. - *
    Provide command line invocation to loop the ping cycle on a configurable broker url. - *
    - * - * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock pair. - * Obtain read lock on all messages, before decrementing the message count. At the end of the on message method add a - * block that obtains the write lock for the very last message, releases any waiting producer. Means that the last - * message waits until all other messages have been handled before releasing producers but allows messages to be - * processed concurrently, unlike the current synchronized block. - */ -public class PingPongProducer implements Runnable, ExceptionListener -{ - /** Used for debugging. */ - private static final Logger log = Logger.getLogger(PingPongProducer.class); - - /** Holds the name of the property to determine whether of not client id is overridden at connection time. */ - public static final String OVERRIDE_CLIENT_ID_PROPNAME = "overrideClientId"; - - /** Holds the default value of the override client id flag. */ - public static final String OVERRIDE_CLIENT_ID_DEAFULT = "false"; - - /** Holds the name of the property to define the JNDI factory name with. */ - public static final String FACTORY_NAME_PROPNAME = "factoryName"; - - /** Holds the default JNDI name of the connection factory. */ - public static final String FACTORY_NAME_DEAFULT = "local"; - - /** Holds the name of the property to set the JNDI initial context properties with. */ - public static final String FILE_PROPERTIES_PROPNAME = "properties"; - - /** Holds the default file name of the JNDI initial context properties. */ - public static final String FILE_PROPERTIES_DEAFULT = "perftests.properties"; - - /** Holds the name of the property to get the test message size from. */ - public static final String MESSAGE_SIZE_PROPNAME = "messageSize"; - - /** Used to set up a default message size. */ - public static final int MESSAGE_SIZE_DEAFULT = 0; - - /** Holds the name of the property to get the ping queue name from. */ - public static final String PING_QUEUE_NAME_PROPNAME = "destinationName"; - - /** Holds the name of the default destination to send pings on. */ - public static final String PING_QUEUE_NAME_DEFAULT = "ping"; - - /** Holds the name of the property to get the queue name postfix from. */ - public static final String QUEUE_NAME_POSTFIX_PROPNAME = "queueNamePostfix"; - - /** Holds the default queue name postfix value. */ - public static final String QUEUE_NAME_POSTFIX_DEFAULT = ""; - - /** Holds the name of the property to get the test delivery mode from. */ - public static final String PERSISTENT_MODE_PROPNAME = "persistent"; - - /** Holds the message delivery mode to use for the test. */ - public static final boolean PERSISTENT_MODE_DEFAULT = false; - - /** Holds the name of the property to get the test transactional mode from. */ - public static final String TRANSACTED_PROPNAME = "transacted"; - - /** Holds the transactional mode to use for the test. */ - public static final boolean TRANSACTED_DEFAULT = false; - - /** Holds the name of the property to get the test consumer transacted mode from. */ - public static final String CONSUMER_TRANSACTED_PROPNAME = "consTransacted"; - - /** Holds the consumer transactional mode default setting. */ - public static final boolean CONSUMER_TRANSACTED_DEFAULT = false; - - /** Holds the name of the property to get the test broker url from. */ - public static final String BROKER_PROPNAME = "broker"; - - /** Holds the default broker url for the test. */ - public static final String BROKER_DEFAULT = "tcp://localhost:5672"; - - /** Holds the name of the property to get the test broker virtual path. */ - public static final String VIRTUAL_HOST_PROPNAME = "virtualHost"; - - /** Holds the default virtual path for the test. */ - public static final String VIRTUAL_HOST_DEFAULT = ""; - - /** Holds the name of the property to get the message rate from. */ - public static final String RATE_PROPNAME = "rate"; - - /** Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. */ - public static final int RATE_DEFAULT = 0; - - /** Holds the name of the property to get the verbose mode proeprty from. */ - public static final String VERBOSE_PROPNAME = "verbose"; - - /** Holds the default verbose mode. */ - public static final boolean VERBOSE_DEFAULT = false; - - /** Holds the name of the property to get the p2p or pub/sub messaging mode from. */ - public static final String PUBSUB_PROPNAME = "pubsub"; - - /** Holds the pub/sub mode default, true means ping a topic, false means ping a queue. */ - public static final boolean PUBSUB_DEFAULT = false; - - /** Holds the name of the property to get the fail after commit flag from. */ - public static final String FAIL_AFTER_COMMIT_PROPNAME = "failAfterCommit"; - - /** Holds the default failover after commit test flag. */ - public static final boolean FAIL_AFTER_COMMIT_DEFAULT = false; - - /** Holds the name of the proeprty to get the fail before commit flag from. */ - public static final String FAIL_BEFORE_COMMIT_PROPNAME = "failBeforeCommit"; - - /** Holds the default failover before commit test flag. */ - public static final boolean FAIL_BEFORE_COMMIT_DEFAULT = false; - - /** Holds the name of the proeprty to get the fail after send flag from. */ - public static final String FAIL_AFTER_SEND_PROPNAME = "failAfterSend"; - - /** Holds the default failover after send test flag. */ - public static final boolean FAIL_AFTER_SEND_DEFAULT = false; - - /** Holds the name of the property to get the fail before send flag from. */ - public static final String FAIL_BEFORE_SEND_PROPNAME = "failBeforeSend"; - - /** Holds the default failover before send test flag. */ - public static final boolean FAIL_BEFORE_SEND_DEFAULT = false; - - /** Holds the name of the property to get the fail once flag from. */ - public static final String FAIL_ONCE_PROPNAME = "failOnce"; - - /** The default failover once flag, true means only do one failover, false means failover on every commit cycle. */ - public static final boolean FAIL_ONCE_DEFAULT = true; - - /** Holds the name of the property to get the broker access username from. */ - public static final String USERNAME_PROPNAME = "username"; - - /** Holds the default broker log on username. */ - public static final String USERNAME_DEFAULT = "guest"; - - /** Holds the name of the property to get the broker access password from. */ - public static final String PASSWORD_PROPNAME = "password"; - - /** Holds the default broker log on password. */ - public static final String PASSWORD_DEFAULT = "guest"; - - /** Holds the name of the proeprty to get the. */ - public static final String SELECTOR_PROPNAME = "selector"; - - /** Holds the default message selector. */ - public static final String SELECTOR_DEFAULT = ""; - - /** Holds the name of the property to get the destination count from. */ - public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; - - /** Defines the default number of destinations to ping. */ - public static final int DESTINATION_COUNT_DEFAULT = 1; - - /** Holds the name of the property to get the number of consumers per destination from. */ - public static final String NUM_CONSUMERS_PROPNAME = "numConsumers"; - - /** Defines the default number consumers per destination. */ - public static final int NUM_CONSUMERS_DEFAULT = 1; - - /** Holds the name of the property to get the waiting timeout for response messages. */ - public static final String TIMEOUT_PROPNAME = "timeout"; - - /** Default time to wait before assuming that a ping has timed out. */ - public static final long TIMEOUT_DEFAULT = 30000; - - /** Holds the name of the property to get the commit batch size from. */ - public static final String TX_BATCH_SIZE_PROPNAME = "commitBatchSize"; - - /** Defines the default number of pings to send in each transaction when running transactionally. */ - public static final int TX_BATCH_SIZE_DEFAULT = 1; - - /** Holds the name of the property to get the unique destinations flag from. */ - public static final String UNIQUE_DESTS_PROPNAME = "uniqueDests"; - - /** Defines the default value for the unique destinations property. */ - public static final boolean UNIQUE_DESTS_DEFAULT = true; - - /** Holds the name of the property to get the durable destinations flag from. */ - public static final String DURABLE_DESTS_PROPNAME = "durableDests"; - - /** Defines the default value of the durable destinations flag. */ - public static final boolean DURABLE_DESTS_DEFAULT = false; - - /** Holds the name of the proeprty to get the message acknowledgement mode from. */ - public static final String ACK_MODE_PROPNAME = "ackMode"; - - /** Defines the default message acknowledgement mode. */ - public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; - - /** Holds the name of the property to get the consumers message acknowledgement mode from. */ - public static final String CONSUMER_ACK_MODE_PROPNAME = "consAckMode"; - - /** Defines the default consumers message acknowledgement mode. */ - public static final int CONSUMER_ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; - - /** Holds the name of the property to get the maximum pending message size setting from. */ - public static final String MAX_PENDING_PROPNAME = "maxPending"; - - /** Defines the default value for the maximum pending message size setting. 0 means no limit. */ - public static final int MAX_PENDING_DEFAULT = 0; - - /** Defines the default prefetch size to use when consuming messages. */ - public static final int PREFETCH_DEFAULT = 100; - - /** Defines the default value of the no local flag to use when consuming messages. */ - public static final boolean NO_LOCAL_DEFAULT = false; - - /** Defines the default value of the exclusive flag to use when consuming messages. */ - public static final boolean EXCLUSIVE_DEFAULT = false; - - /** Holds the name of the property to store nanosecond timestamps in ping messages with. */ - public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp"; - - /** Holds the default configuration properties. */ - public static ParsedProperties defaults = new ParsedProperties(); - - static - { - defaults.setPropertyIfNull(OVERRIDE_CLIENT_ID_PROPNAME, OVERRIDE_CLIENT_ID_DEAFULT); - defaults.setPropertyIfNull(FILE_PROPERTIES_PROPNAME, FILE_PROPERTIES_DEAFULT); - defaults.setPropertyIfNull(FACTORY_NAME_PROPNAME, FACTORY_NAME_DEAFULT); - defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT); - defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT); - defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT); - defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT); - defaults.setPropertyIfNull(PING_QUEUE_NAME_PROPNAME, PING_QUEUE_NAME_DEFAULT); - defaults.setPropertyIfNull(QUEUE_NAME_POSTFIX_PROPNAME, QUEUE_NAME_POSTFIX_DEFAULT); - defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT); - defaults.setPropertyIfNull(TRANSACTED_PROPNAME, TRANSACTED_DEFAULT); - defaults.setPropertyIfNull(CONSUMER_TRANSACTED_PROPNAME, CONSUMER_TRANSACTED_DEFAULT); - defaults.setPropertyIfNull(PERSISTENT_MODE_PROPNAME, PERSISTENT_MODE_DEFAULT); - defaults.setPropertyIfNull(ACK_MODE_PROPNAME, ACK_MODE_DEFAULT); - defaults.setPropertyIfNull(CONSUMER_ACK_MODE_PROPNAME, CONSUMER_ACK_MODE_DEFAULT); - defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT); - defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT); - defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT); - defaults.setPropertyIfNull(UNIQUE_DESTS_PROPNAME, UNIQUE_DESTS_DEFAULT); - defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT); - defaults.setPropertyIfNull(FAIL_BEFORE_COMMIT_PROPNAME, FAIL_BEFORE_COMMIT_DEFAULT); - defaults.setPropertyIfNull(FAIL_AFTER_COMMIT_PROPNAME, FAIL_AFTER_COMMIT_DEFAULT); - defaults.setPropertyIfNull(FAIL_BEFORE_SEND_PROPNAME, FAIL_BEFORE_SEND_DEFAULT); - defaults.setPropertyIfNull(FAIL_AFTER_SEND_PROPNAME, FAIL_AFTER_SEND_DEFAULT); - defaults.setPropertyIfNull(FAIL_ONCE_PROPNAME, FAIL_ONCE_DEFAULT); - defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT); - defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT); - defaults.setPropertyIfNull(NUM_CONSUMERS_PROPNAME, NUM_CONSUMERS_DEFAULT); - defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT); - defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT); - defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT); - } - - /** Allows setting of client ID on the connection, rather than through the connection URL. */ - protected boolean _overrideClientId; - - /** Holds the JNDI name of the JMS connection factory. */ - protected String _factoryName; - - /** Holds the name of the properties file to configure JNDI with. */ - protected String _fileProperties; - - /** Holds the broker url. */ - protected String _brokerDetails; - - /** Holds the username to access the broker with. */ - protected String _username; - - /** Holds the password to access the broker with. */ - protected String _password; - - /** Holds the virtual host on the broker to run the tests through. */ - protected String _virtualpath; - - /** Holds the root name from which to generate test destination names. */ - protected String _destinationName; - - /** Holds the default queue name postfix value. */ - protected String _queueNamePostfix; - - /** Holds the message selector to filter the pings with. */ - protected String _selector; - - /** Holds the producers transactional mode flag. */ - protected boolean _transacted; - - /** Holds the consumers transactional mode flag. */ - protected boolean _consTransacted; - - /** Determines whether this producer sends persistent messages. */ - protected boolean _persistent; - - /** Holds the acknowledgement mode used for the producers. */ - protected int _ackMode; - - /** Holds the acknowledgement mode setting for the consumers. */ - protected int _consAckMode; - - /** Determines what size of messages this producer sends. */ - protected int _messageSize; - - /** Used to indicate that the ping loop should print out whenever it pings. */ - protected boolean _verbose; - - /** Flag used to indicate if this is a point to point or pub/sub ping client. */ - protected boolean _isPubSub; - - /** Flag used to indicate if the destinations should be unique client. */ - protected boolean _isUnique; - - /** Flag used to indicate that durable destination should be used. */ - protected boolean _isDurable; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ - protected boolean _failBeforeCommit; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ - protected boolean _failAfterCommit; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ - protected boolean _failBeforeSend; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ - protected boolean _failAfterSend; - - /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ - protected boolean _failOnce; - - /** Holds the number of sends that should be performed in every transaction when using transactions. */ - protected int _txBatchSize; - - /** Holds the number of destinations to ping. */ - protected int _noOfDestinations; - - /** Holds the number of consumers per destination. */ - protected int _noOfConsumers; - - /** Holds the maximum send rate in herz. */ - protected int _rate; - - /** - * Holds the size of the maximum amount of pending data that the client should buffer, sending is suspended - * if this limit is breached. - */ - protected int _maxPendingSize; - - /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ - private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); - - /** A source for providing sequential unqiue ids for instances of this class to be identifed with. */ - private static AtomicInteger _instanceIdGenerator = new AtomicInteger(0); - - /** Holds this instances unique id. */ - private int instanceId; - - /** - * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross multiple - * ping producers on the same JVM. - */ - private static Map perCorrelationIds = - Collections.synchronizedMap(new HashMap()); - - /** A convenient formatter to use when time stamping output. */ - protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); - - /** Holds the connection for the message producer. */ - protected Connection _connection; - - /** Holds the consumer connections. */ - protected Connection[] _consumerConnection; - - /** Holds the controlSession on which ping replies are received. */ - protected Session[] _consumerSession; - - /** Holds the producer controlSession, needed to create ping messages. */ - protected Session _producerSession; - - /** Holds the destination where the response messages will arrive. */ - protected Destination _replyDestination; - - /** Holds the set of destinations that this ping producer pings. */ - protected List _pingDestinations; - - /** Used to restrict the sending rate to a specified limit. */ - protected Throttle _rateLimiter; - - /** Holds a message listener that this message listener chains all its messages to. */ - protected ChainedMessageListener _chainedMessageListener = null; - - /** - * This id generator is used to generate ids to append to the queue name to ensure that queues can be unique when - * creating multiple ping producers in the same JVM. - */ - protected static AtomicInteger _queueJVMSequenceID = new AtomicInteger(); - - /** - * This id generator is used to generates ids that are only unique within this pinger. Creating multiple pingers - * on the same JVM using this id generator will allow them to ping on the same queues. - */ - protected AtomicInteger _queueSharedID = new AtomicInteger(); - - /** Used to tell the ping loop when to terminate, it only runs while this is true. */ - protected boolean _publish = true; - - /** Holds the message producer to send the pings through. */ - protected MessageProducer _producer; - - /** Holds the message consumer to receive the ping replies through. */ - protected MessageConsumer[] _consumer; - - /** The prompt to display when asking the user to kill the broker for failover testing. */ - private static final String KILL_BROKER_PROMPT = "Kill broker now, then press Return."; - - /** Holds the name for this test client to be identified to the broker with. */ - private String _clientID; - - /** Keeps count of the total messages sent purely for debugging purposes. */ - private static AtomicInteger numSent = new AtomicInteger(); - - /** - * Holds a monitor which is used to synchronize sender and receivers threads, where the sender has elected - * to wait until the number of unreceived message is reduced before continuing to send. This monitor is a - * fair SynchronousQueue becuase that provides fair scheduling, to ensure that all producer threads get an - * equal chance to produce messages. - */ - static final SynchronousQueue _sendPauseMonitor = new SynchronousQueue(true); - - /** Keeps a count of the number of message currently sent but not received. */ - static AtomicInteger _unreceived = new AtomicInteger(0); - - /** - * Creates a ping producer with the specified parameters, of which there are many. See the class level comments - * for details. This constructor creates a connection to the broker and creates producer and consumer sessions on - * it, to send and recieve its pings and replies on. - * - * @param overrides Properties containing any desired overrides to the defaults. - * - * @throws Exception Any exceptions are allowed to fall through. - */ - public PingPongProducer(Properties overrides) throws Exception - { - // log.debug("public PingPongProducer(Properties overrides = " + overrides + "): called"); - instanceId = _instanceIdGenerator.getAndIncrement(); - - // Create a set of parsed properties from the defaults overriden by the passed in values. - ParsedProperties properties = new ParsedProperties(defaults); - properties.putAll(overrides); - - // Extract the configuration properties to set the pinger up with. - _overrideClientId = properties.getPropertyAsBoolean(OVERRIDE_CLIENT_ID_PROPNAME); - _factoryName = properties.getProperty(FACTORY_NAME_PROPNAME); - _fileProperties = properties.getProperty(FILE_PROPERTIES_PROPNAME); - _brokerDetails = properties.getProperty(BROKER_PROPNAME); - _username = properties.getProperty(USERNAME_PROPNAME); - _password = properties.getProperty(PASSWORD_PROPNAME); - _virtualpath = properties.getProperty(VIRTUAL_HOST_PROPNAME); - _destinationName = properties.getProperty(PING_QUEUE_NAME_PROPNAME); - _queueNamePostfix = properties.getProperty(QUEUE_NAME_POSTFIX_PROPNAME); - _selector = properties.getProperty(SELECTOR_PROPNAME); - _transacted = properties.getPropertyAsBoolean(TRANSACTED_PROPNAME); - _consTransacted = properties.getPropertyAsBoolean(CONSUMER_TRANSACTED_PROPNAME); - _persistent = properties.getPropertyAsBoolean(PERSISTENT_MODE_PROPNAME); - _messageSize = properties.getPropertyAsInteger(MESSAGE_SIZE_PROPNAME); - _verbose = properties.getPropertyAsBoolean(VERBOSE_PROPNAME); - _failAfterCommit = properties.getPropertyAsBoolean(FAIL_AFTER_COMMIT_PROPNAME); - _failBeforeCommit = properties.getPropertyAsBoolean(FAIL_BEFORE_COMMIT_PROPNAME); - _failAfterSend = properties.getPropertyAsBoolean(FAIL_AFTER_SEND_PROPNAME); - _failBeforeSend = properties.getPropertyAsBoolean(FAIL_BEFORE_SEND_PROPNAME); - _failOnce = properties.getPropertyAsBoolean(FAIL_ONCE_PROPNAME); - _txBatchSize = properties.getPropertyAsInteger(TX_BATCH_SIZE_PROPNAME); - _noOfDestinations = properties.getPropertyAsInteger(DESTINATION_COUNT_PROPNAME); - _noOfConsumers = properties.getPropertyAsInteger(NUM_CONSUMERS_PROPNAME); - _rate = properties.getPropertyAsInteger(RATE_PROPNAME); - _isPubSub = properties.getPropertyAsBoolean(PUBSUB_PROPNAME); - _isUnique = properties.getPropertyAsBoolean(UNIQUE_DESTS_PROPNAME); - _isDurable = properties.getPropertyAsBoolean(DURABLE_DESTS_PROPNAME); - _ackMode = _transacted ? 0 : properties.getPropertyAsInteger(ACK_MODE_PROPNAME); - _consAckMode = _consTransacted ? 0 : properties.getPropertyAsInteger(CONSUMER_ACK_MODE_PROPNAME); - _maxPendingSize = properties.getPropertyAsInteger(MAX_PENDING_PROPNAME); - - // Check that one or more destinations were specified. - if (_noOfDestinations < 1) - { - throw new IllegalArgumentException("There must be at least one destination."); - } - - // Set up a throttle to control the send rate, if a rate > 0 is specified. - if (_rate > 0) - { - _rateLimiter = new BatchedThrottle(); - _rateLimiter.setRate(_rate); - } - - // Create the connection and message producers/consumers. - // establishConnection(true, true); - } - - /** - * Establishes a connection to the broker and creates message consumers and producers based on the parameters - * that this ping client was created with. - * - * @param producer Flag to indicate whether or not the producer should be set up. - * @param consumer Flag to indicate whether or not the consumers should be set up. - * - * @throws Exception Any exceptions are allowed to fall through. - */ - public void establishConnection(boolean producer, boolean consumer) throws Exception - { - // log.debug("public void establishConnection(): called"); - - // Generate a unique identifying name for this client, based on it ip address and the current time. - InetAddress address = InetAddress.getLocalHost(); - // _clientID = address.getHostName() + System.currentTimeMillis(); - _clientID = "perftest_" + instanceId; - - // Create a connection to the broker. - createConnection(_clientID); - - // Create transactional or non-transactional sessions, based on the command line arguments. - _producerSession = _connection.createSession(_transacted, _ackMode); - - _consumerSession = new Session[_noOfConsumers]; - - for (int i = 0; i < _noOfConsumers; i++) - { - _consumerSession[i] = _consumerConnection[i].createSession(_consTransacted, _consAckMode); - } - - // Create the destinations to send pings to and receive replies from. - _replyDestination = _consumerSession[0].createTemporaryQueue(); - createPingDestinations(_noOfDestinations, _selector, _destinationName, _isUnique, _isDurable); - - // Create the message producer only if instructed to. - if (producer) - { - createProducer(); - } - - // Create the message consumer only if instructed to. - if (consumer) - { - createReplyConsumers(getReplyDestinations(), _selector); - } - } - - /** - * Establishes a connection to the broker, based on the configuration parameters that this ping client was - * created with. - * - * @param clientID The clients identifier. - * - * @throws JMSException Underlying exceptions allowed to fall through. - * @throws NamingException Underlying exceptions allowed to fall through. - * @throws IOException Underlying exceptions allowed to fall through. - */ - protected void createConnection(String clientID) throws JMSException, NamingException, IOException - { - // _log.debug("protected void createConnection(String clientID = " + clientID + "): called"); - - // _log.debug("Creating a connection for the message producer."); - - - Context context = InitialContextHelper.getInitialContext(_fileProperties); - ConnectionFactory factory = (ConnectionFactory) context.lookup(_factoryName); - _connection = factory.createConnection(_username, _password); - - if (_overrideClientId) - { - _connection.setClientID(clientID); - } - - // _log.debug("Creating " + _noOfConsumers + " connections for the consumers."); - - _consumerConnection = new Connection[_noOfConsumers]; - - for (int i = 0; i < _noOfConsumers; i++) - { - _consumerConnection[i] = factory.createConnection(_username, _password); - // _consumerConnection[i].setClientID(clientID); - } - } - - /** - * Starts a ping-pong loop running from the command line. The bounce back client {@link PingPongBouncer} also needs - * to be started to bounce the pings back again. - * - * @param args The command line arguments. - */ - public static void main(String[] args) - { - try - { - Properties options = - CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); - - // Create a ping producer overriding its defaults with all options passed on the command line. - PingPongProducer pingProducer = new PingPongProducer(options); - pingProducer.establishConnection(true, true); - - // Start the ping producers dispatch thread running. - pingProducer._connection.start(); - - // Create a shutdown hook to terminate the ping-pong producer. - Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); - - // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. - pingProducer._connection.setExceptionListener(pingProducer); - - // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. - Thread pingThread = new Thread(pingProducer); - pingThread.run(); - pingThread.join(); - } - catch (Exception e) - { - System.err.println(e.getMessage()); - log.error("Top level handler caught execption.", e); - System.exit(1); - } - } - - /** - * Convenience method for a short pause. - * - * @param sleepTime The time in milliseconds to pause for. - */ - public static void pause(long sleepTime) - { - if (sleepTime > 0) - { - try - { - Thread.sleep(sleepTime); - } - catch (InterruptedException ie) - { } - } - } - - /** - * Gets all the reply destinations (to listen for replies on). In this case this will just be the single reply to - * destination of this pinger. - * - * @return The single reply to destination of this pinger, wrapped in a list. - */ - public List getReplyDestinations() - { - // log.debug("public List getReplyDestinations(): called"); - - List replyDestinations = new ArrayList(); - replyDestinations.add(_replyDestination); - - // log.debug("replyDestinations = " + replyDestinations); - - return replyDestinations; - } - - /** - * Creates the producer to send the pings on. This is created without a default destination. Its persistent delivery - * flag is set accoring the ping producer creation options. - * - * @throws JMSException Any JMSExceptions are allowed to fall through. - */ - public void createProducer() throws JMSException - { - // log.debug("public void createProducer(): called"); - - _producer = (MessageProducer) _producerSession.createProducer(null); - _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - - // log.debug("Created producer for " + (_persistent ? "persistent" : "non-persistent") + " messages."); - } - - /** - * Creates consumers for the specified number of destinations. The destinations themselves are also created by this - * method. - * - * @param noOfDestinations The number of destinations to create consumers for. - * @param selector The message selector to filter the consumers with. - * @param rootName The root of the name, or actual name if only one is being created. - * @param unique true to make the destinations unique to this pinger, false to share the - * numbering with all pingers on the same JVM. - * @param durable If the destinations are durable topics. - * - * @throws JMSException Any JMSExceptions are allowed to fall through. - */ - public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique, - boolean durable) throws JMSException - { - /*log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " - + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = " - + durable + "): called");*/ - - _pingDestinations = new ArrayList(); - - // Create the desired number of ping destinations and consumers for them. - // log.debug("Creating " + noOfDestinations + " destinations to ping."); - - for (int i = 0; i < noOfDestinations; i++) - { - Destination destination; - String id; - - // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag. - if (unique) - { - // log.debug("Creating unique destinations."); - id = "_" + _queueJVMSequenceID.incrementAndGet() + "_" + _connection.getClientID(); - } - else - { - // log.debug("Creating shared destinations."); - id = "_" + _queueSharedID.incrementAndGet(); - } - - // Check if this is a pub/sub pinger, in which case create topics. - if (_isPubSub) - { - destination = _producerSession.createTopic(rootName + id); - // log.debug("Created non-durable topic " + destination); - - if (durable) - { - _producerSession.createDurableSubscriber((Topic) destination, _connection.getClientID()); - } - } - // Otherwise this is a p2p pinger, in which case create queues. - else - { - destination = _producerSession.createQueue(rootName + id + _queueNamePostfix); - // log.debug("Created queue " + destination); - } - - // Keep the destination. - _pingDestinations.add(destination); - } - } - - /** - * Creates consumers for the specified destinations and registers this pinger to listen to their messages. - * - * @param destinations The destinations to listen to. - * @param selector A selector to filter the messages with. - * - * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through. - */ - public void createReplyConsumers(Collection destinations, String selector) throws JMSException - { - /*log.debug("public void createReplyConsumers(Collection destinations = " + destinations - + ", String selector = " + selector + "): called");*/ - - log.debug("There are " + destinations.size() + " destinations."); - log.debug("Creating " + _noOfConsumers + " consumers on each destination."); - log.debug("Total number of consumers is: " + (destinations.size() * _noOfConsumers)); - - for (Destination destination : destinations) - { - _consumer = new MessageConsumer[_noOfConsumers]; - - for (int i = 0; i < _noOfConsumers; i++) - { - // Create a consumer for the destination and set this pinger to listen to its messages. - _consumer[i] = _consumerSession[i].createConsumer(destination, selector, NO_LOCAL_DEFAULT); - - final int consumerNo = i; - - _consumer[i].setMessageListener(new MessageListener() - { - public void onMessage(Message message) - { - onMessageWithConsumerNo(message, consumerNo); - } - }); - - log.debug("Set consumer " + i + " to listen to replies sent to destination: " + destination); - } - } - } - - /** - * Stores the received message in the replies map, then resets the boolean latch that a thread waiting for a - * correlating reply may be waiting on. This is only done if the reply has a correlation id that is expected in the - * replies map. - * - * @param message The received message. - * @param consumerNo The consumer number within this test pinger instance. - */ - public void onMessageWithConsumerNo(Message message, int consumerNo) - { - // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo = " + consumerNo + "): called"); - try - { - long now = System.nanoTime(); - long timestamp = getTimestamp(message); - long pingTime = now - timestamp; - - // NDC.push("id" + instanceId + "/cons" + consumerNo); - - // Extract the messages correlation id. - String correlationID = message.getJMSCorrelationID(); - // log.debug("correlationID = " + correlationID); - - // int num = message.getIntProperty("MSG_NUM"); - // log.info("Message " + num + " received."); - - boolean isRedelivered = message.getJMSRedelivered(); - // log.debug("isRedelivered = " + isRedelivered); - - if (!isRedelivered) - { - // Countdown on the traffic light if there is one for the matching correlation id. - PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); - - if (perCorrelationId != null) - { - CountDownLatch trafficLight = perCorrelationId.trafficLight; - - // Restart the timeout timer on every message. - perCorrelationId.timeOutStart = System.nanoTime(); - - // log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); - - // Release waiting senders if there are some and using maxPending limit. - if ((_maxPendingSize > 0)) - { - // Decrement the count of sent but not yet received messages. - int unreceived = _unreceived.decrementAndGet(); - int unreceivedSize = - (unreceived * ((_messageSize == 0) ? 1 : _messageSize)) - / (_isPubSub ? getConsumersPerDestination() : 1); - - // log.debug("unreceived = " + unreceived); - // log.debug("unreceivedSize = " + unreceivedSize); - - // synchronized (_sendPauseMonitor) - // { - if (unreceivedSize < _maxPendingSize) - { - _sendPauseMonitor.poll(); - } - // } - } - - // Decrement the countdown latch. Before this point, it is possible that two threads might enter this - // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block - // ensures that each thread will get a unique value for the remaining messages. - long trueCount; - long remainingCount; - - synchronized (trafficLight) - { - trafficLight.countDown(); - - trueCount = trafficLight.getCount(); - remainingCount = trueCount - 1; - - // NDC.push("/rem" + remainingCount); - - // log.debug("remainingCount = " + remainingCount); - // log.debug("trueCount = " + trueCount); - - // Commit on transaction batch size boundaries. At this point in time the waiting producer - // remains blocked, even on the last message. - // Commit count is divided by noOfConsumers in p2p mode, so that each consumer only commits on - // each batch boundary. For pub/sub each consumer gets every message so no division is done. - // When running in client ack mode, an ack is done instead of a commit, on the commit batch - // size boundaries. - long commitCount = _isPubSub ? remainingCount : (remainingCount / _noOfConsumers); - // log.debug("commitCount = " + commitCount); - - if ((commitCount % _txBatchSize) == 0) - { - if (_consAckMode == 2) - { - // log.debug("Doing client ack for consumer " + consumerNo + "."); - message.acknowledge(); - } - else - { - // log.debug("Trying commit for consumer " + consumerNo + "."); - commitTx(_consumerSession[consumerNo]); - // log.info("Tx committed on consumer " + consumerNo); - } - } - - // Forward the message and remaining count to any interested chained message listener. - if (_chainedMessageListener != null) - { - _chainedMessageListener.onMessage(message, (int) remainingCount, pingTime); - } - - // Check if this is the last message, in which case release any waiting producers. This is done - // after the transaction has been committed and any listeners notified. - if (trueCount == 1) - { - trafficLight.countDown(); - } - } - } - else - { - log.warn("Got unexpected message with correlationId: " + correlationID); - } - } - else - { - log.warn("Got redelivered message, ignoring."); - } - } - catch (JMSException e) - { - log.warn("There was a JMSException: " + e.getMessage(), e); - } - finally - { - // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo): ending"); - // NDC.clear(); - } - } - - /** - * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out - * before a reply arrives, then a null reply is returned from this method. This method allows the caller to specify - * the correlation id. - * - * @param message The message to send. If this is null, one is generated. - * @param numPings The number of ping messages to send. - * @param timeout The timeout in milliseconds. - * @param messageCorrelationId The message correlation id. If this is null, one is generated. - * - * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait - * for all prematurely. - * - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - * @throws InterruptedException When interrupted by a timeout - */ - public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) - throws JMSException, InterruptedException - { - /*log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " - + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ - - // Generate a unique correlation id to put on the messages before sending them, if one was not specified. - if (messageCorrelationId == null) - { - messageCorrelationId = Long.toString(_correlationIdGenerator.incrementAndGet()); - } - - try - { - // NDC.push("prod"); - - // Create a count down latch to count the number of replies with. This is created before the messages are - // sent so that the replies cannot be received before the count down is created. - // One is added to this, so that the last reply becomes a special case. The special case is that the - // chained message listener must be called before this sender can be unblocked, but that decrementing the - // countdown needs to be done before the chained listener can be called. - PerCorrelationId perCorrelationId = new PerCorrelationId(); - - perCorrelationId.trafficLight = new CountDownLatch(getExpectedNumPings(numPings) + 1); - perCorrelationIds.put(messageCorrelationId, perCorrelationId); - - // Set up the current time as the start time for pinging on the correlation id. This is used to determine - // timeouts. - perCorrelationId.timeOutStart = System.nanoTime(); - - // Send the specifed number of messages. - pingNoWaitForReply(message, numPings, messageCorrelationId); - - boolean timedOut; - boolean allMessagesReceived; - int numReplies; - - do - { - // Block the current thread until replies to all the messages are received, or it times out. - perCorrelationId.trafficLight.await(timeout, TimeUnit.MILLISECONDS); - - // Work out how many replies were receieved. - numReplies = getExpectedNumPings(numPings) - (int) perCorrelationId.trafficLight.getCount(); - - allMessagesReceived = numReplies == getExpectedNumPings(numPings); - - // log.debug("numReplies = " + numReplies); - // log.debug("allMessagesReceived = " + allMessagesReceived); - - // Recheck the timeout condition. - long now = System.nanoTime(); - long lastMessageReceievedAt = perCorrelationId.timeOutStart; - timedOut = (now - lastMessageReceievedAt) > (timeout * 1000000); - - // log.debug("now = " + now); - // log.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); - } - while (!timedOut && !allMessagesReceived); - - if ((numReplies < getExpectedNumPings(numPings)) && _verbose) - { - log.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); - } - else if (_verbose) - { - log.info("Got all replies on id, " + messageCorrelationId); - } - - // commitTx(_consumerSession); - - // log.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); - - return numReplies; - } - // Ensure that the message countdown latch is always removed from the reply map. The reply map is long lived, - // so will be a memory leak if this is not done. - finally - { - // NDC.pop(); - perCorrelationIds.remove(messageCorrelationId); - } - } - - /** - * Sends the specified number of ping messages and does not wait for correlating replies. - * - * @param message The message to send. - * @param numPings The number of pings to send. - * @param messageCorrelationId A correlation id to place on all messages sent. - * - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - */ - public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException - { - /*log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings - + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ - - if (message == null) - { - message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent); - } - - message.setJMSCorrelationID(messageCorrelationId); - - // Set up a committed flag to detect uncommitted messages at the end of the send loop. This may occurr if the - // transaction batch size is not a factor of the number of pings. In which case an extra commit at the end is - // needed. - boolean committed = false; - - // Send all of the ping messages. - for (int i = 0; i < numPings; i++) - { - // Re-timestamp the message. - // message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); - - // Send the message, passing in the message count. - committed = sendMessage(i, message); - - // Spew out per message timings on every message sonly in verbose mode. - /*if (_verbose) - { - log.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); - }*/ - } - - // Call commit if the send loop finished before reaching a batch size boundary so there may still be uncommitted messages. - if (!committed) - { - commitTx(_producerSession); - } - } - - /** - * Sends the sepcified message, applies rate limiting and possibly commits the current transaction. The count of - * messages sent so far must be specified and is used to round robin the ping destinations (where there are more - * than one), and to determine if the transaction batch size has been reached and the sent messages should be - * committed. - * - * @param i The count of messages sent so far in a loop of multiple calls to this send method. - * @param message The message to send. - * - * @return true if the messages were committed, false otherwise. - * - * @throws JMSException All underlyiung JMSExceptions are allowed to fall through. - */ - protected boolean sendMessage(int i, Message message) throws JMSException - { - try - { - NDC.push("id" + instanceId + "/prod"); - - // log.debug("protected boolean sendMessage(int i = " + i + ", Message message): called"); - // log.debug("_txBatchSize = " + _txBatchSize); - - // Round robin the destinations as the messages are sent. - Destination destination = _pingDestinations.get(i % _pingDestinations.size()); - - // Prompt the user to kill the broker when doing failover testing. - _failBeforeSend = waitForUserToPromptOnFailure(_failBeforeSend); - - // Get the test setup for the correlation id. - String correlationID = message.getJMSCorrelationID(); - PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); - - // If necessary, wait until the max pending message size comes within its limit. - if (_maxPendingSize > 0) - { - synchronized (_sendPauseMonitor) - { - // Used to keep track of the number of times that send has to wait. - int numWaits = 0; - - // The maximum number of waits before the test gives up and fails. This has been chosen to correspond with - // the test timeout. - int waitLimit = (int) (TIMEOUT_DEFAULT / 10000); - - while (true) - { - // Get the size estimate of sent but not yet received messages. - int unreceived = _unreceived.get(); - int unreceivedSize = - (unreceived * ((_messageSize == 0) ? 1 : _messageSize)) - / (_isPubSub ? getConsumersPerDestination() : 1); - - // log.debug("unreceived = " + unreceived); - // log.debug("unreceivedSize = " + unreceivedSize); - // log.debug("_maxPendingSize = " + _maxPendingSize); - - if (unreceivedSize > _maxPendingSize) - { - // log.debug("unreceived size estimate over limit = " + unreceivedSize); - - // Fail the test if the send has had to wait more than the maximum allowed number of times. - if (numWaits > waitLimit) - { - String errorMessage = - "Send has had to wait for the unreceivedSize (" + unreceivedSize - + ") to come below the maxPendingSize (" + _maxPendingSize + ") more that " + waitLimit - + " times."; - log.warn(errorMessage); - throw new RuntimeException(errorMessage); - } - - // Wait on the send pause barrier for the limit to be re-established. - try - { - long start = System.nanoTime(); - // _sendPauseMonitor.wait(10000); - _sendPauseMonitor.offer(new Object(), 10000, TimeUnit.MILLISECONDS); - long end = System.nanoTime(); - - // Count the wait only if it was for > 99% of the requested wait time. - if (((float) (end - start) / (float) (10000 * 1000000L)) > 0.99) - { - numWaits++; - } - } - catch (InterruptedException e) - { - // Restore the interrupted status - Thread.currentThread().interrupt(); - throw new RuntimeException(e); - } - } - else - { - break; - } - } - } - } - - // Send the message either to its round robin destination, or its default destination. - // int num = numSent.incrementAndGet(); - // message.setIntProperty("MSG_NUM", num); - setTimestamp(message); - - if (destination == null) - { - _producer.send(message); - } - else - { - _producer.send(destination, message); - } - - // Increase the unreceived size, this may actually happen after the message is received. - // The unreceived size is incremented by the number of consumers that will get a copy of the message, - // in pub/sub mode. - if (_maxPendingSize > 0) - { - int newUnreceivedCount = _unreceived.addAndGet(_isPubSub ? getConsumersPerDestination() : 1); - // log.debug("newUnreceivedCount = " + newUnreceivedCount); - } - - // Apply message rate throttling if a rate limit has been set up. - if (_rateLimiter != null) - { - _rateLimiter.throttle(); - } - - // Call commit every time the commit batch size is reached. - boolean committed = false; - - // Commit on every transaction batch size boundary. Here i + 1 is the count of actual messages sent. - if (((i + 1) % _txBatchSize) == 0) - { - // log.debug("Trying commit on producer session."); - committed = commitTx(_producerSession); - } - - return committed; - } - finally - { - NDC.clear(); - } - } - - /** - * If the specified fail flag is set, this method waits for the user to cause a failure and then indicate to the - * test that the failure has occurred, before the method returns. - * - * @param failFlag The fail flag to test. - * - * @return The new value for the fail flag. If the {@link #_failOnce} flag is set, then each fail flag is only - * used once, then reset. - */ - private boolean waitForUserToPromptOnFailure(boolean failFlag) - { - if (failFlag) - { - if (_failOnce) - { - failFlag = false; - } - - // log.debug("Failing Before Send"); - waitForUser(KILL_BROKER_PROMPT); - } - - return failFlag; - } - - /** - * Implements a single iteration of the ping loop. This sends the number of pings specified by the transaction batch - * size property, and waits for replies to all of them. Any errors cause the publish flag to be cleared, which will - * terminate the pinger. - */ - public void pingLoop() - { - try - { - // Generate a sample message and time stamp it. - Message msg = getTestMessage(_replyDestination, _messageSize, _persistent); - // setTimestamp(msg); - - // Send the message and wait for a reply. - pingAndWaitForReply(msg, TX_BATCH_SIZE_DEFAULT, TIMEOUT_DEFAULT, null); - } - catch (JMSException e) - { - _publish = false; - // log.debug("There was a JMSException: " + e.getMessage(), e); - } - catch (InterruptedException e) - { - _publish = false; - // log.debug("There was an interruption: " + e.getMessage(), e); - } - } - - /** - * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set - * here. - * - * @param messageListener The chained message listener. - */ - public void setChainedMessageListener(ChainedMessageListener messageListener) - { - _chainedMessageListener = messageListener; - } - - /** Removes any chained message listeners from this pinger. */ - public void removeChainedMessageListener() - { - _chainedMessageListener = null; - } - - /** - * Generates a test message of the specified size, with the specified reply-to destination and persistence flag. - * - * @param replyQueue The reply-to destination for the message. - * @param messageSize The desired size of the message in bytes. - * @param persistent true if the message should use persistent delivery, false otherwise. - * - * @return A freshly generated test message. - * - * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. - */ - public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException - { - // return TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); - return TestUtils.createTestMessageOfSize(_producerSession, messageSize); - } - - /** - * Sets the current time in nanoseconds as the timestamp on the message. - * - * @param msg The message to timestamp. - * - * @throws JMSException Any JMSExceptions are allowed to fall through. - */ - protected void setTimestamp(Message msg) throws JMSException - { - /*if (((AMQSession)_producerSession).isStrictAMQP()) - { - ((AMQMessage)msg).setTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME), System.nanoTime()); - } - else - {*/ - msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); - // } - } - - /** - * Extracts the nanosecond timestamp from a message. - * - * @param msg The message to extract the time stamp from. - * - * @return The timestamp in nanos. - * - * @throws JMSException Any JMSExceptions are allowed to fall through. - */ - protected long getTimestamp(Message msg) throws JMSException - { - /*if (((AMQSession)_producerSession).isStrictAMQP()) - { - Long value = ((AMQMessage)msg).getTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME)); - - return (value == null) ? 0L : value; - } - else - {*/ - return msg.getLongProperty(PingPongProducer.MESSAGE_TIMESTAMP_PROPNAME); - // } - } - - /** - * Stops the ping loop by clearing the publish flag. The current loop will complete when it notices that this flag - * has been cleared. - */ - public void stop() - { - _publish = false; - } - - /** - * Starts the producer and consumer connections. - * - * @throws JMSException Any JMSExceptions are allowed to fall through. - */ - public void start() throws JMSException - { - // log.debug("public void start(): called"); - - _connection.start(); - // log.debug("Producer started."); - - for (int i = 0; i < _noOfConsumers; i++) - { - _consumerConnection[i].start(); - // log.debug("Consumer " + i + " started."); - } - } - - /** Implements a ping loop that repeatedly pings until the publish flag becomes false. */ - public void run() - { - // Keep running until the publish flag is cleared. - while (_publish) - { - pingLoop(); - } - } - - /** - * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the - * connection, this clears the publish flag which in turn will halt the ping loop. - * - * @param e The exception that triggered this callback method. - */ - public void onException(JMSException e) - { - // log.debug("public void onException(JMSException e = " + e + "): called", e); - _publish = false; - } - - /** - * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered - * with the runtime system as a shutdown hook. - * - * @return A shutdown hook for the ping loop. - */ - public Thread getShutdownHook() - { - return new Thread(new Runnable() - { - public void run() - { - stop(); - } - }); - } - - /** - * Closes all of the producer and consumer connections. - * - * @throws JMSException All JMSException are allowed to fall through. - */ - public void close() throws JMSException - { - // log.debug("public void close(): called"); - - try - { - if (_connection != null) - { - // log.debug("Before close producer connection."); - _connection.close(); - // log.debug("Closed producer connection."); - } - - for (int i = 0; i < _noOfConsumers; i++) - { - if (_consumerConnection[i] != null) - { - // log.debug("Before close consumer connection " + i + "."); - _consumerConnection[i].close(); - // log.debug("Closed consumer connection " + i + "."); - } - } - } - finally - { - _connection = null; - _producerSession = null; - _consumerSession = null; - _consumerConnection = null; - _producer = null; - _consumer = null; - _pingDestinations = null; - _replyDestination = null; - } - } - - /** - * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not a - * transactional controlSession, this method does nothing (unless the failover after send flag is set). - * - *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit is - * applied. This flag applies whether the pinger is transactional or not. - * - *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the commit - * is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker after the - * commit is applied. These flags will only apply if using a transactional pinger. - * - * @param session The controlSession to commit - * - * @return true if the controlSession was committed, false if it was not. - * - * @throws javax.jms.JMSException If the commit fails and then the rollback fails. - * - * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit - * method, because commits only apply to transactional pingers, but fail after send applied to transactional and - * non-transactional alike. - */ - protected boolean commitTx(Session session) throws JMSException - { - // log.debug("protected void commitTx(Session session): called"); - - boolean committed = false; - - _failAfterSend = waitForUserToPromptOnFailure(_failAfterSend); - - if (session.getTransacted()) - { - // log.debug("Session is transacted."); - - try - { - _failBeforeCommit = waitForUserToPromptOnFailure(_failBeforeCommit); - - long start = System.nanoTime(); - session.commit(); - committed = true; - // log.debug("Time taken to commit :" + ((System.nanoTime() - start) / 1000000f) + " ms"); - - _failAfterCommit = waitForUserToPromptOnFailure(_failAfterCommit); - - // log.debug("Session Commited."); - } - catch (JMSException e) - { - // log.debug("JMSException on commit:" + e.getMessage(), e); - - try - { - session.rollback(); - // log.debug("Message rolled back."); - } - catch (JMSException jmse) - { - // log.debug("JMSE on rollback:" + jmse.getMessage(), jmse); - - // Both commit and rollback failed. Throw the rollback exception. - throw jmse; - } - } - } - - return committed; - } - - /** - * Outputs a prompt to the console and waits for the user to press return. - * - * @param prompt The prompt to display on the console. - */ - public void waitForUser(String prompt) - { - System.out.println(prompt); - - try - { - System.in.read(); - } - catch (IOException e) - { - // Ignored. - } - - System.out.println("Continuing."); - } - - /** - * Gets the number of consumers that are listening to each destination in the test. - * - * @return int The number of consumers subscribing to each topic. - */ - public int getConsumersPerDestination() - { - return _noOfConsumers; - } - - /** - * Calculates how many pings are expected to be received for the given number sent. - * - * @param numpings The number of pings that will be sent. - * - * @return The number that should be received, for the test to pass. - */ - public int getExpectedNumPings(int numpings) - { - // log.debug("public int getExpectedNumPings(int numpings = " + numpings + "): called"); - - // log.debug("Each ping will be received by " + (_isPubSub ? getConsumersPerDestination() : 1) + " consumers."); - - return numpings * (_isPubSub ? getConsumersPerDestination() : 1); - } - - /** - * Defines a chained message listener interface that can be attached to this pinger. Whenever this pinger's {@link - * PingPongProducer#onMessageWithConsumerNo} method is called, the chained listener set through the {@link - * PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected count of - * messages with that correlation id. - * - *

    Provided only one pinger is producing messages with that correlation id, the chained listener will always be - * given unique message counts. It will always be called while the producer waiting for all messages to arrive is - * still blocked. - */ - public static interface ChainedMessageListener - { - /** - * Notifies interested listeners about message arrival and important test stats, the number of messages - * remaining in the test, and the messages send timestamp. - * - * @param message The newly arrived message. - * @param remainingCount The number of messages left to complete the test. - * @param latency The nanosecond latency of the message. - * - * @throws JMSException Any JMS exceptions is allowed to fall through. - */ - public void onMessage(Message message, int remainingCount, long latency) throws JMSException; - } - - /** - * Holds information on each correlation id. The countdown latch, the current timeout timer... More stuff to be - * added to this: read/write lock to make onMessage more concurrent as described in class header comment. - */ - protected static class PerCorrelationId - { - /** Holds a countdown on number of expected messages. */ - CountDownLatch trafficLight; - - /** Holds the last timestamp that the timeout was reset to. */ - Long timeOutStart; - } -} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java deleted file mode 100644 index 780589768f..0000000000 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * - * 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.qpid.requestreply; - -import junit.framework.Assert; -import junit.framework.Test; -import junit.framework.TestSuite; - -import org.apache.log4j.Logger; - -import uk.co.thebadgerset.junit.extensions.AsymptoticTestCase; -import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; -import uk.co.thebadgerset.junit.extensions.util.TestContextProperties; - -import javax.jms.*; - -/** - * PingPongTestPerf is a full round trip ping test, that has been written with the intention of being scaled up to run - * many times simultaneously to simluate many clients/producer/connections. A full round trip ping sends a message from - * a producer to a conumer, then the consumer replies to the message on a temporary queue. - * - *

    A single run of the test using the default JUnit test runner will result in the sending and timing of the number - * of pings specified by the test size and time how long it takes for all of these to complete. This test may be scaled - * up using a suitable JUnit test runner. See {@link uk.co.thebadgerset.junit.extensions.TKTestRunner} for more - * information on how to do this. - * - *

    The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a - * temporary queue for replies. This setup is only established once for all the test repeats, but each test threads - * gets its own connection/producer/consumer, this is only re-established if the connection is lost. - * - *

    The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that - * is the name of the temporary queue, fires off many messages on the original queue and waits for them all to come - * back on the temporary queue. - * - *

    Configurable test properties: message size, transacted or not, persistent or not. Broker connection details. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    - */ -public class PingPongTestPerf extends AsymptoticTestCase -{ - private static Logger _logger = Logger.getLogger(PingPongTestPerf.class); - - /** Thread local to hold the per-thread test setup fields. */ - ThreadLocal threadSetup = new ThreadLocal(); - - // Set up a property reader to extract the test parameters from. Once ContextualProperties is available in - // the project dependencies, use it to get property overrides for configurable tests and to notify the test runner - // of the test parameters to log with the results. It also providers some basic type parsing convenience methods. - // private Properties testParameters = System.getProperties(); - private ParsedProperties testParameters = - TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/); - - public PingPongTestPerf(String name) - { - super(name); - - _logger.debug(testParameters); - - // Sets up the test parameters with defaults. - /*testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME, - Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.MESSAGE_SIZE_PROPNAME, - Integer.toString(PingPongProducer.MESSAGE_SIZE_DEAFULT)); - testParameters.setPropertyIfNull(PingPongProducer.PING_QUEUE_NAME_PROPNAME, - PingPongProducer.PING_QUEUE_NAME_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.PERSISTENT_MODE_PROPNAME, - Boolean.toString(PingPongProducer.PERSISTENT_MODE_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.TRANSACTED_PROPNAME, - Boolean.toString(PingPongProducer.TRANSACTED_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.BROKER_PROPNAME, PingPongProducer.BROKER_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.USERNAME_PROPNAME, PingPongProducer.USERNAME_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.PASSWORD_PROPNAME, PingPongProducer.PASSWORD_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.VIRTUAL_HOST_PROPNAME, PingPongProducer.VIRTUAL_HOST_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.VERBOSE_PROPNAME, - Boolean.toString(PingPongProducer.VERBOSE_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.RATE_PROPNAME, Integer.toString(PingPongProducer.RATE_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.PUBSUB_PROPNAME, - Boolean.toString(PingPongProducer.PUBSUB_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME, - Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.TIMEOUT_PROPNAME, Long.toString(PingPongProducer.TIMEOUT_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.DESTINATION_COUNT_PROPNAME, - Integer.toString(PingPongProducer.DESTINATION_COUNT_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_COMMIT_PROPNAME, - PingPongProducer.FAIL_AFTER_COMMIT_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_COMMIT_PROPNAME, - PingPongProducer.FAIL_BEFORE_COMMIT_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_SEND_PROPNAME, - PingPongProducer.FAIL_AFTER_SEND_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_SEND_PROPNAME, - PingPongProducer.FAIL_BEFORE_SEND_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.FAIL_ONCE_PROPNAME, PingPongProducer.FAIL_ONCE_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.UNIQUE_DESTS_PROPNAME, - Boolean.toString(PingPongProducer.UNIQUE_DESTS_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.ACK_MODE_PROPNAME, - Integer.toString(PingPongProducer.ACK_MODE_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.PAUSE_AFTER_BATCH_PROPNAME, - PingPongProducer.PAUSE_AFTER_BATCH_DEFAULT);*/ - } - - /** - * Compile all the tests into a test suite. - */ - public static Test suite() - { - // Build a new test suite - TestSuite suite = new TestSuite("Ping-Pong Performance Tests"); - - // Run performance tests in read committed mode. - suite.addTest(new PingPongTestPerf("testPingPongOk")); - - return suite; - } - - private static void setSystemPropertyIfNull(String propName, String propValue) - { - if (System.getProperty(propName) == null) - { - System.setProperty(propName, propValue); - } - } - - public void testPingPongOk(int numPings) throws Exception - { - // Get the per thread test setup to run the test through. - PerThreadSetup perThreadSetup = threadSetup.get(); - - // Generate a sample message. This message is already time stamped and has its reply-to destination set. - Message msg = - perThreadSetup._testPingProducer.getTestMessage(perThreadSetup._testPingProducer.getReplyDestinations().get(0), - testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), - testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); - - // Send the message and wait for a reply. - int numReplies = - perThreadSetup._testPingProducer.pingAndWaitForReply(msg, numPings, PingPongProducer.TIMEOUT_DEFAULT, null); - - // Fail the test if the timeout was exceeded. - if (numReplies != numPings) - { - Assert.fail("The ping timed out, got " + numReplies + " out of " + numPings); - } - } - - /** - * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. - */ - public void threadSetUp() - { - try - { - PerThreadSetup perThreadSetup = new PerThreadSetup(); - - // Extract the test set up paramaeters. - String fileProperties = testParameters.getProperty(PingPongProducer.FILE_PROPERTIES_PROPNAME); - String factoryName = testParameters.getProperty(PingPongProducer.FACTORY_NAME_PROPNAME); - String username = testParameters.getProperty(PingPongProducer.USERNAME_PROPNAME); - String password = testParameters.getProperty(PingPongProducer.PASSWORD_PROPNAME); - String destinationName = testParameters.getProperty(PingPongProducer.PING_QUEUE_NAME_PROPNAME); - boolean persistent = testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME); - boolean transacted = testParameters.getPropertyAsBoolean(PingPongProducer.TRANSACTED_PROPNAME); - String selector = testParameters.getProperty(PingPongProducer.SELECTOR_PROPNAME); - boolean verbose = testParameters.getPropertyAsBoolean(PingPongProducer.VERBOSE_PROPNAME); - boolean pubsub = testParameters.getPropertyAsBoolean(PingPongProducer.PUBSUB_PROPNAME); - - synchronized (this) - { - // Establish a bounce back client on the ping queue to bounce back the pings. - perThreadSetup._testPingBouncer = - new PingPongBouncer(fileProperties, factoryName, username, password, destinationName, persistent, - transacted, selector, verbose, pubsub); - - // Start the connections for client and producer running. - perThreadSetup._testPingBouncer.getConnection().start(); - - // Establish a ping-pong client on the ping queue to send the pings and receive replies with. - perThreadSetup._testPingProducer = new PingPongProducer(testParameters); - perThreadSetup._testPingProducer.establishConnection(true, true); - perThreadSetup._testPingProducer.start(); - } - - // Attach the per-thread set to the thread. - threadSetup.set(perThreadSetup); - } - catch (Exception e) - { - _logger.warn("There was an exception during per thread setup.", e); - } - } - - /** - * Performs test fixture clean - */ - public void threadTearDown() - { - _logger.debug("public void threadTearDown(): called"); - - try - { - // Get the per thread test fixture. - PerThreadSetup perThreadSetup = threadSetup.get(); - - // Close the pingers so that it cleans up its connection cleanly. - synchronized (this) - { - perThreadSetup._testPingProducer.close(); - // perThreadSetup._testPingBouncer.close(); - } - - // Ensure the per thread fixture is reclaimed. - threadSetup.remove(); - } - catch (JMSException e) - { - _logger.warn("There was an exception during per thread tear down."); - } - } - - protected static class PerThreadSetup - { - /** - * Holds the test ping-pong producer. - */ - private PingPongProducer _testPingProducer; - - /** - * Holds the test ping client. - */ - private PingPongBouncer _testPingBouncer; - } -} -- cgit v1.2.1 From 00f30eaf668ed07f16c9151947093150877e07f7 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Thu, 24 Apr 2008 00:04:01 +0000 Subject: QPID-832 copy from M2.x git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@651117 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/client/message/TestMessageFactory.java | 121 ++ .../config/AMQConnectionFactoryInitialiser.java | 35 + .../org/apache/qpid/config/AbstractConfig.java | 69 + .../qpid/config/ConnectionFactoryInitialiser.java | 29 + .../java/org/apache/qpid/config/Connector.java | 40 + .../org/apache/qpid/config/ConnectorConfig.java | 28 + .../config/JBossConnectionFactoryInitialiser.java | 112 ++ .../main/java/org/apache/qpid/oldtopic/Config.java | 243 +++ .../java/org/apache/qpid/oldtopic/Listener.java | 141 ++ .../org/apache/qpid/oldtopic/MessageFactory.java | 153 ++ .../java/org/apache/qpid/oldtopic/Publisher.java | 175 ++ .../org/apache/qpid/ping/PingAsyncTestPerf.java | 292 ++++ .../main/java/org/apache/qpid/ping/PingClient.java | 107 ++ .../org/apache/qpid/ping/PingDurableClient.java | 452 +++++ .../org/apache/qpid/ping/PingLatencyTestPerf.java | 311 ++++ .../org/apache/qpid/ping/PingSendOnlyClient.java | 93 ++ .../java/org/apache/qpid/ping/PingTestPerf.java | 196 +++ .../apache/qpid/requestreply/PingPongBouncer.java | 453 ++++++ .../apache/qpid/requestreply/PingPongProducer.java | 1720 ++++++++++++++++++++ .../apache/qpid/requestreply/PingPongTestPerf.java | 251 +++ .../qpid/test/testcases/MessageThroughputPerf.java | 199 +++ .../main/java/org/apache/qpid/topic/Config.java | 326 ++++ .../main/java/org/apache/qpid/topic/Listener.java | 303 ++++ .../java/org/apache/qpid/topic/MessageFactory.java | 157 ++ .../main/java/org/apache/qpid/topic/Publisher.java | 186 +++ 25 files changed, 6192 insertions(+) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/Connector.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/Config.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/Listener.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/MessageFactory.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/Publisher.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java new file mode 100644 index 0000000000..64ccb719b6 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java @@ -0,0 +1,121 @@ +/* + * + * 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.qpid.client.message; + +import org.apache.mina.common.ByteBuffer; +import org.apache.mina.common.SimpleByteBufferAllocator; + +import javax.jms.JMSException; +import javax.jms.Session; +import javax.jms.ObjectMessage; +import javax.jms.StreamMessage; +import javax.jms.BytesMessage; +import javax.jms.TextMessage; +import javax.jms.Queue; +import javax.jms.DeliveryMode; +import javax.jms.Destination; + +public class TestMessageFactory +{ + private static final String MESSAGE_DATA_BYTES = "-message payload-message paylaod-message payload-message paylaod"; + + public static TextMessage newTextMessage(Session session, int size) throws JMSException + { + return session.createTextMessage(createMessagePayload(size)); + } + + public static JMSTextMessage newJMSTextMessage(int size, String encoding) throws JMSException + { + ByteBuffer byteBuffer = (new SimpleByteBufferAllocator()).allocate(size, true); + JMSTextMessage message = new JMSTextMessage(byteBuffer, encoding); + message.clearBody(); + message.setText(createMessagePayload(size)); + return message; + } + + public static BytesMessage newBytesMessage(Session session, int size) throws JMSException + { + BytesMessage message = session.createBytesMessage(); + message.writeUTF(createMessagePayload(size)); + return message; + } + + public static StreamMessage newStreamMessage(Session session, int size) throws JMSException + { + StreamMessage message = session.createStreamMessage(); + message.writeString(createMessagePayload(size)); + return message; + } + + public static ObjectMessage newObjectMessage(Session session, int size) throws JMSException + { + if (size == 0) + { + return session.createObjectMessage(); + } + else + { + return session.createObjectMessage(createMessagePayload(size)); + } + } + + /** + * Creates an ObjectMessage with given size and sets the JMS properties (JMSReplyTo and DeliveryMode) + * @param session + * @param replyDestination + * @param size + * @param persistent + * @return the new ObjectMessage + * @throws JMSException + */ + public static ObjectMessage newObjectMessage(Session session, Destination replyDestination, int size, boolean persistent) throws JMSException + { + ObjectMessage msg = newObjectMessage(session, size); + + // Set the messages persistent delivery flag. + msg.setJMSDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + // Ensure that the temporary reply queue is set as the reply to destination for the message. + if (replyDestination != null) + { + msg.setJMSReplyTo(replyDestination); + } + + return msg; + } + + public static String createMessagePayload(int size) + { + StringBuffer buf = new StringBuffer(size); + int count = 0; + while (count <= (size - MESSAGE_DATA_BYTES.length())) + { + buf.append(MESSAGE_DATA_BYTES); + count += MESSAGE_DATA_BYTES.length(); + } + if (count < size) + { + buf.append(MESSAGE_DATA_BYTES, 0, size - count); + } + + return buf.toString(); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java new file mode 100644 index 0000000000..cac0064785 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AMQConnectionFactoryInitialiser.java @@ -0,0 +1,35 @@ +/* + * + * 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.qpid.config; + +import org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.config.ConnectionFactoryInitialiser; +import org.apache.qpid.config.ConnectorConfig; + +import javax.jms.ConnectionFactory; + +class AMQConnectionFactoryInitialiser implements ConnectionFactoryInitialiser +{ + public ConnectionFactory getFactory(ConnectorConfig config) + { + return new AMQConnectionFactory(config.getHost(), config.getPort(), "/test_path"); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java new file mode 100644 index 0000000000..14db74438f --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java @@ -0,0 +1,69 @@ +/* + * + * 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.qpid.config; + +public abstract class AbstractConfig +{ + public boolean setOptions(String[] argv) + { + try + { + for(int i = 0; i < argv.length - 1; i += 2) + { + String key = argv[i]; + String value = argv[i+1]; + setOption(key, value); + } + return true; + } + catch(Exception e) + { + System.out.println(e.getMessage()); + } + return false; + } + + protected int parseInt(String msg, String i) + { + try + { + return Integer.parseInt(i); + } + catch(NumberFormatException e) + { + throw new RuntimeException(msg + ": " + i, e); + } + } + + protected long parseLong(String msg, String i) + { + try + { + return Long.parseLong(i); + } + catch(NumberFormatException e) + { + throw new RuntimeException(msg + ": " + i, e); + } + } + + public abstract void setOption(String key, String value); +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java new file mode 100644 index 0000000000..a9984eb09a --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectionFactoryInitialiser.java @@ -0,0 +1,29 @@ +/* + * + * 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.qpid.config; + +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; + +public interface ConnectionFactoryInitialiser +{ + public ConnectionFactory getFactory(ConnectorConfig config) throws JMSException; +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/Connector.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/Connector.java new file mode 100644 index 0000000000..ff2377f087 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/Connector.java @@ -0,0 +1,40 @@ +/* + * + * 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.qpid.config; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; + +public class Connector +{ + public Connection createConnection(ConnectorConfig config) throws Exception + { + return getConnectionFactory(config).createConnection(); + } + + ConnectionFactory getConnectionFactory(ConnectorConfig config) throws Exception + { + String factory = config.getFactory(); + if(factory == null) factory = AMQConnectionFactoryInitialiser.class.getName(); + System.out.println("Using " + factory); + return ((ConnectionFactoryInitialiser) Class.forName(factory).newInstance()).getFactory(config); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java new file mode 100644 index 0000000000..b120ed3f12 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/ConnectorConfig.java @@ -0,0 +1,28 @@ +/* + * + * 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.qpid.config; + +public interface ConnectorConfig +{ + public String getHost(); + public int getPort(); + public String getFactory(); +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java new file mode 100644 index 0000000000..a0248a8f79 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java @@ -0,0 +1,112 @@ +/* + * + * 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.qpid.config; + +import org.apache.qpid.config.ConnectionFactoryInitialiser; +import org.apache.qpid.config.ConnectorConfig; +import org.apache.qpid.client.JMSAMQException; + +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.MBeanException; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.naming.NameNotFoundException; +import java.util.Hashtable; + +public class JBossConnectionFactoryInitialiser implements ConnectionFactoryInitialiser +{ + public ConnectionFactory getFactory(ConnectorConfig config) throws JMSException + { + ConnectionFactory cf = null; + InitialContext ic = null; + Hashtable ht = new Hashtable(); + ht.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); + String jbossHost = System.getProperty("jboss.host", "eqd-lxamq01"); + String jbossPort = System.getProperty("jboss.port", "1099"); + ht.put(InitialContext.PROVIDER_URL, "jnp://" + jbossHost + ":" + jbossPort); + ht.put(InitialContext.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); + + try + { + ic = new InitialContext(ht); + if (!doesDestinationExist("topictest.messages", ic)) + { + deployTopic("topictest.messages", ic); + } + if (!doesDestinationExist("topictest.control", ic)) + { + deployTopic("topictest.control", ic); + } + + cf = (ConnectionFactory) ic.lookup("/ConnectionFactory"); + return cf; + } + catch (NamingException e) + { + throw new JMSAMQException("Unable to lookup object: " + e, e); + } + catch (Exception e) + { + throw new JMSAMQException("Error creating topic: " + e, e); + } + } + + private boolean doesDestinationExist(String name, InitialContext ic) throws Exception + { + try + { + ic.lookup("/" + name); + } + catch (NameNotFoundException e) + { + return false; + } + return true; + } + + private void deployTopic(String name, InitialContext ic) throws Exception + { + MBeanServerConnection mBeanServer = lookupMBeanServerProxy(ic); + + ObjectName serverObjectName = new ObjectName("jboss.messaging:service=ServerPeer"); + + String jndiName = "/" + name; + try + { + mBeanServer.invoke(serverObjectName, "createTopic", + new Object[]{name, jndiName}, + new String[]{"java.lang.String", "java.lang.String"}); + } + catch (MBeanException e) + { + System.err.println("Error: " + e); + System.err.println("Cause: " + e.getCause()); + } + } + + private MBeanServerConnection lookupMBeanServerProxy(InitialContext ic) throws NamingException + { + return (MBeanServerConnection) ic.lookup("jmx/invoker/RMIAdaptor"); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/Config.java b/qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/Config.java new file mode 100644 index 0000000000..5b6169ed2d --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/Config.java @@ -0,0 +1,243 @@ +/* + * + * 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.qpid.oldtopic; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.config.ConnectorConfig; +import org.apache.qpid.config.ConnectionFactoryInitialiser; +import org.apache.qpid.config.Connector; +import org.apache.qpid.config.AbstractConfig; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; + +class Config extends AbstractConfig implements ConnectorConfig +{ + + private String host = "localhost"; + private int port = 5672; + private String factory = null; + + private int payload = 256; + private int messages = 1000; + private int clients = 1; + private int batch = 1; + private long delay = 1; + private int warmup; + private int ackMode= AMQSession.NO_ACKNOWLEDGE; + private String clientId; + private String subscriptionId; + private boolean persistent; + + public Config() + { + } + + int getAckMode() + { + return ackMode; + } + + void setPayload(int payload) + { + this.payload = payload; + } + + int getPayload() + { + return payload; + } + + void setClients(int clients) + { + this.clients = clients; + } + + int getClients() + { + return clients; + } + + void setMessages(int messages) + { + this.messages = messages; + } + + int getMessages() + { + return messages; + } + + public String getHost() + { + return host; + } + + public void setHost(String host) + { + this.host = host; + } + + public int getPort() + { + return port; + } + + public String getFactory() + { + return factory; + } + + public void setPort(int port) + { + this.port = port; + } + + int getBatch() + { + return batch; + } + + void setBatch(int batch) + { + this.batch = batch; + } + + int getWarmup() + { + return warmup; + } + + void setWarmup(int warmup) + { + this.warmup = warmup; + } + + public long getDelay() + { + return delay; + } + + public void setDelay(long delay) + { + this.delay = delay; + } + + String getClientId() + { + return clientId; + } + + String getSubscriptionId() + { + return subscriptionId; + } + + boolean usePersistentMessages() + { + return persistent; + } + + public void setOption(String key, String value) + { + if("-host".equalsIgnoreCase(key)) + { + setHost(value); + } + else if("-port".equalsIgnoreCase(key)) + { + try + { + setPort(Integer.parseInt(value)); + } + catch(NumberFormatException e) + { + throw new RuntimeException("Bad port number: " + value); + } + } + else if("-payload".equalsIgnoreCase(key)) + { + setPayload(parseInt("Bad payload size", value)); + } + else if("-messages".equalsIgnoreCase(key)) + { + setMessages(parseInt("Bad message count", value)); + } + else if("-clients".equalsIgnoreCase(key)) + { + setClients(parseInt("Bad client count", value)); + } + else if("-batch".equalsIgnoreCase(key)) + { + setBatch(parseInt("Bad batch count", value)); + } + else if("-delay".equalsIgnoreCase(key)) + { + setDelay(parseLong("Bad batch delay", value)); + } + else if("-warmup".equalsIgnoreCase(key)) + { + setWarmup(parseInt("Bad warmup count", value)); + } + else if("-ack".equalsIgnoreCase(key)) + { + ackMode = parseInt("Bad ack mode", value); + } + else if("-factory".equalsIgnoreCase(key)) + { + factory = value; + } + else if("-clientId".equalsIgnoreCase(key)) + { + clientId = value; + } + else if("-subscriptionId".equalsIgnoreCase(key)) + { + subscriptionId = value; + } + else if("-persistent".equalsIgnoreCase(key)) + { + persistent = "true".equalsIgnoreCase(value); + } + else + { + System.out.println("Ignoring unrecognised option: " + key); + } + } + + static String getAckModeDescription(int ackMode) + { + switch(ackMode) + { + case AMQSession.NO_ACKNOWLEDGE: return "NO_ACKNOWLEDGE"; + case AMQSession.AUTO_ACKNOWLEDGE: return "AUTO_ACKNOWLEDGE"; + case AMQSession.CLIENT_ACKNOWLEDGE: return "CLIENT_ACKNOWLEDGE"; + case AMQSession.DUPS_OK_ACKNOWLEDGE: return "DUPS_OK_ACKNOWELDGE"; + case AMQSession.PRE_ACKNOWLEDGE: return "PRE_ACKNOWLEDGE"; + } + return "AckMode=" + ackMode; + } + + public Connection createConnection() throws Exception + { + return new Connector().createConnection(this); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/Listener.java b/qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/Listener.java new file mode 100644 index 0000000000..4732782d4c --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/Listener.java @@ -0,0 +1,141 @@ +/* + * + * 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.qpid.oldtopic; +import org.apache.log4j.*; +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +public class Listener implements MessageListener +{ + private final Connection _connection; + private final MessageProducer _controller; + private final javax.jms.Session _session; + private final MessageFactory _factory; + private boolean init; + private int count; + private long start; + + Listener(Connection connection, int ackMode) throws Exception + { + this(connection, ackMode, null); + } + + Listener(Connection connection, int ackMode, String name) throws Exception + { + _connection = connection; + _session = connection.createSession(false, ackMode); + _factory = new MessageFactory(_session); + + //register for events + if(name == null) + { + _factory.createTopicConsumer().setMessageListener(this); + } + else + { + _factory.createDurableTopicConsumer(name).setMessageListener(this); + } + + _connection.start(); + + _controller = _factory.createControlPublisher(); + System.out.println("Waiting for messages " + + Config.getAckModeDescription(ackMode) + + (name == null ? "" : " (subscribed with name " + name + " and client id " + connection.getClientID() + ")") + + "..."); + + } + + private void shutdown() + { + try + { + _session.close(); + _connection.stop(); + _connection.close(); + } + catch(Exception e) + { + e.printStackTrace(System.out); + } + } + + private void report() + { + try + { + String msg = getReport(); + _controller.send(_factory.createReportResponseMessage(msg)); + System.out.println("Sent report: " + msg); + } + catch(Exception e) + { + e.printStackTrace(System.out); + } + } + + private String getReport() + { + long time = (System.currentTimeMillis() - start); + return "Received " + count + " in " + time + "ms"; + } + + public void onMessage(Message message) + { + if(!init) + { + start = System.currentTimeMillis(); + count = 0; + init = true; + } + + if(_factory.isShutdown(message)) + { + shutdown(); + } + else if(_factory.isReport(message)) + { + //send a report: + report(); + init = false; + } + else if (++count % 100 == 0) + { + System.out.println("Received " + count + " messages."); + } + } + + public static void main(String[] argv) throws Exception + { + Config config = new Config(); + config.setOptions(argv); + + Connection con = config.createConnection(); + if(config.getClientId() != null) + { + con.setClientID(config.getClientId()); + } + new Listener(con, config.getAckMode(), config.getSubscriptionId()); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/MessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/MessageFactory.java new file mode 100644 index 0000000000..b2fbeb7e35 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/MessageFactory.java @@ -0,0 +1,153 @@ +/* + * + * 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.qpid.oldtopic; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; + +import javax.jms.*; + +/** + */ +class MessageFactory +{ + private static final char[] DATA = "abcdefghijklmnopqrstuvwxyz".toCharArray(); + + private final Session _session; + private final Topic _topic; + private final Topic _control; + private final byte[] _payload; + + + MessageFactory(Session session) throws JMSException + { + this(session, 256); + } + + MessageFactory(Session session, int size) throws JMSException + { + _session = session; +/* if(session instanceof AMQSession) + { + _topic = new AMQTopic("topictest.messages"); + _control = new AMQTopic("topictest.control"); + } + else*/ + { + _topic = session.createTopic("topictest.messages"); + _control = session.createTopic("topictest.control"); + } + _payload = new byte[size]; + + for(int i = 0; i < size; i++) + { + _payload[i] = (byte) DATA[i % DATA.length]; + } + } + + Topic getTopic() + { + return _topic; + } + + Message createEventMessage() throws JMSException + { + BytesMessage msg = _session.createBytesMessage(); + msg.writeBytes(_payload); + return msg; + } + + Message createShutdownMessage() throws JMSException + { + return _session.createTextMessage("SHUTDOWN"); + } + + Message createReportRequestMessage() throws JMSException + { + return _session.createTextMessage("REPORT"); + } + + Message createReportResponseMessage(String msg) throws JMSException + { + return _session.createTextMessage(msg); + } + + boolean isShutdown(Message m) + { + return checkText(m, "SHUTDOWN"); + } + + boolean isReport(Message m) + { + return checkText(m, "REPORT"); + } + + Object getReport(Message m) + { + try + { + return ((TextMessage) m).getText(); + } + catch (JMSException e) + { + e.printStackTrace(System.out); + return e.toString(); + } + } + + MessageConsumer createTopicConsumer() throws Exception + { + return _session.createConsumer(_topic); + } + + MessageConsumer createDurableTopicConsumer(String name) throws Exception + { + return _session.createDurableSubscriber(_topic, name); + } + + MessageConsumer createControlConsumer() throws Exception + { + return _session.createConsumer(_control); + } + + MessageProducer createTopicPublisher() throws Exception + { + return _session.createProducer(_topic); + } + + MessageProducer createControlPublisher() throws Exception + { + return _session.createProducer(_control); + } + + private static boolean checkText(Message m, String s) + { + try + { + return m instanceof TextMessage && ((TextMessage) m).getText().equals(s); + } + catch (JMSException e) + { + e.printStackTrace(System.out); + return false; + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/Publisher.java b/qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/Publisher.java new file mode 100644 index 0000000000..f811704323 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/oldtopic/Publisher.java @@ -0,0 +1,175 @@ +/* + * + * 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.qpid.oldtopic; + +import javax.jms.*; + +public class Publisher implements MessageListener +{ + private final Object _lock = new Object(); + private final Connection _connection; + private final Session _session; + private final MessageFactory _factory; + private final MessageProducer _publisher; + private int _count; + + Publisher(Connection connection, int size, int ackMode, boolean persistent) throws Exception + { + _connection = connection; + _session = _connection.createSession(false, ackMode); + _factory = new MessageFactory(_session, size); + _publisher = _factory.createTopicPublisher(); + _publisher.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + System.out.println("Publishing " + (persistent ? "persistent" : "non-persistent") + " messages of " + size + " bytes, " + Config.getAckModeDescription(ackMode) + "."); + } + + private void test(Config config) throws Exception + { + test(config.getBatch(), config.getDelay(), config.getMessages(), config.getClients(), config.getWarmup()); + } + + private void test(int batches, long delay, int msgCount, int consumerCount, int warmup) throws Exception + { + _factory.createControlConsumer().setMessageListener(this); + _connection.start(); + + if(warmup > 0) + { + System.out.println("Runing warmup (" + warmup + " msgs)"); + long time = batch(warmup, consumerCount); + System.out.println("Warmup completed in " + time + "ms"); + } + + long[] times = new long[batches]; + for(int i = 0; i < batches; i++) + { + if(i > 0) Thread.sleep(delay*1000); + times[i] = batch(msgCount, consumerCount); + System.out.println("Batch " + (i+1) + " of " + batches + " completed in " + times[i] + " ms."); + } + + long min = min(times); + long max = max(times); + System.out.println("min: " + min + ", max: " + max + " avg: " + avg(times, min, max)); + + //request shutdown + _publisher.send(_factory.createShutdownMessage()); + + _connection.stop(); + _connection.close(); + } + + private long batch(int msgCount, int consumerCount) throws Exception + { + _count = consumerCount; + long start = System.currentTimeMillis(); + publish(msgCount); + waitForCompletion(consumerCount); + return System.currentTimeMillis() - start; + } + + private void publish(int count) throws Exception + { + + //send events + for (int i = 0; i < count; i++) + { + _publisher.send(_factory.createEventMessage()); + if ((i + 1) % 100 == 0) + { + System.out.println("Sent " + (i + 1) + " messages"); + } + } + + //request report + _publisher.send(_factory.createReportRequestMessage()); + } + + private void waitForCompletion(int consumers) throws Exception + { + System.out.println("Waiting for completion..."); + synchronized (_lock) + { + while (_count > 0) + { + _lock.wait(); + } + } + } + + + public void onMessage(Message message) + { + System.out.println("Received report " + _factory.getReport(message) + " " + --_count + " remaining"); + if (_count == 0) + { + synchronized (_lock) + { + _lock.notify(); + } + } + } + + static long min(long[] times) + { + long min = times.length > 0 ? times[0] : 0; + for(int i = 0; i < times.length; i++) + { + min = Math.min(min, times[i]); + } + return min; + } + + static long max(long[] times) + { + long max = times.length > 0 ? times[0] : 0; + for(int i = 0; i < times.length; i++) + { + max = Math.max(max, times[i]); + } + return max; + } + + static long avg(long[] times, long min, long max) + { + long sum = 0; + for(int i = 0; i < times.length; i++) + { + sum += times[i]; + } + sum -= min; + sum -= max; + + return (sum / (times.length - 2)); + } + + public static void main(String[] argv) throws Exception + { + Config config = new Config(); + config.setOptions(argv); + + Connection con = config.createConnection(); + int size = config.getPayload(); + int ackMode = config.getAckMode(); + boolean persistent = config.usePersistentMessages(); + new Publisher(con, size, ackMode, persistent).test(config); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java new file mode 100644 index 0000000000..89fc805a34 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java @@ -0,0 +1,292 @@ +/* + * + * 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.qpid.ping; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +import org.apache.qpid.requestreply.PingPongProducer; + +import org.apache.qpid.junit.extensions.TimingController; +import org.apache.qpid.junit.extensions.TimingControllerAware; + +import javax.jms.JMSException; +import javax.jms.Message; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +/** + * PingAsyncTestPerf is a performance test that outputs multiple timings from its test method, using the timing controller + * interface supplied by the test runner from a seperate listener thread. It differs from the {@link PingTestPerf} test + * that it extends because it can output timings as replies are received, rather than waiting until all expected replies + * are received. This is less 'blocky' than the tests in {@link PingTestPerf}, and provides a truer simulation of sending + * and recieving clients working asynchronously. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Send many ping messages and output timings asynchronously on batches received. + *
    + */ +public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerAware +{ + private static Logger _logger = Logger.getLogger(PingAsyncTestPerf.class); + + /** Holds the name of the property to get the test results logging batch size. */ + public static final String TEST_RESULTS_BATCH_SIZE_PROPNAME = "batchSize"; + + /** Holds the default test results logging batch size. */ + public static final int TEST_RESULTS_BATCH_SIZE_DEFAULT = 1000; + + /** Used to hold the timing controller passed from the test runner. */ + private TimingController _timingController; + + /** Used to generate unique correlation ids for each test run. */ + private AtomicLong corellationIdGenerator = new AtomicLong(); + + /** Holds test specifics by correlation id. This consists of the expected number of messages and the timing controler. */ + private Map perCorrelationIds = + Collections.synchronizedMap(new HashMap()); + + /** Holds the batched results listener, that does logging on batch boundaries. */ + private BatchedResultsListener batchedResultsListener = null; + + /** + * Creates a new asynchronous ping performance test with the specified name. + * + * @param name The test name. + */ + public PingAsyncTestPerf(String name) + { + super(name); + + // Sets up the test parameters with defaults. + testParameters.setPropertyIfNull(TEST_RESULTS_BATCH_SIZE_PROPNAME, + Integer.toString(TEST_RESULTS_BATCH_SIZE_DEFAULT)); + } + + /** + * Compile all the tests into a test suite. + * @return The test suite to run. Should only contain testAsyncPingOk method. + */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Ping Performance Tests"); + + // Run performance tests in read committed mode. + suite.addTest(new PingAsyncTestPerf("testAsyncPingOk")); + + return suite; + } + + /** + * Accepts a timing controller from the test runner. + * + * @param timingController The timing controller to register mutliple timings with. + */ + public void setTimingController(TimingController timingController) + { + _timingController = timingController; + } + + /** + * Gets the timing controller passed in by the test runner. + * + * @return The timing controller passed in by the test runner. + */ + public TimingController getTimingController() + { + return _timingController; + } + + /** + * Sends the specified number of pings, asynchronously outputs timings on every batch boundary, and waits until + * all replies have been received or a time out occurs before exiting this method. + * + * @param numPings The number of pings to send. + * @throws Exception pass all errors out to the test harness + */ + public void testAsyncPingOk(int numPings) throws Exception + { + // _logger.debug("public void testAsyncPingOk(int numPings): called"); + + // Ensure that at least one ping was requeusted. + if (numPings == 0) + { + _logger.error("Number of pings requested was zero."); + fail("Number of pings requested was zero."); + } + + // Get the per thread test setup to run the test through. + PerThreadSetup perThreadSetup = threadSetup.get(); + PingClient pingClient = perThreadSetup._pingClient; + + // Advance the correlation id of messages to send, to make it unique for this run. + perThreadSetup._correlationId = Long.toString(corellationIdGenerator.incrementAndGet()); + // String messageCorrelationId = perThreadSetup._correlationId; + // _logger.debug("messageCorrelationId = " + messageCorrelationId); + + // Initialize the count and timing controller for the new correlation id. + PerCorrelationId perCorrelationId = new PerCorrelationId(); + TimingController tc = getTimingController().getControllerForCurrentThread(); + perCorrelationId._tc = tc; + perCorrelationId._expectedCount = pingClient.getExpectedNumPings(numPings); + perCorrelationIds.put(perThreadSetup._correlationId, perCorrelationId); + + // Send the requested number of messages, and wait until they have all been received. + long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); + int numReplies = pingClient.pingAndWaitForReply(null, numPings, timeout, perThreadSetup._correlationId); + + // Check that all the replies were received and log a fail if they were not. + if (numReplies < perCorrelationId._expectedCount) + { + perCorrelationId._tc.completeTest(false, numPings - perCorrelationId._expectedCount); + } + + // Remove the expected count and timing controller for the message correlation id, to ensure they are cleaned up. + perCorrelationIds.remove(perThreadSetup._correlationId); + } + + /** + * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. + */ + public void threadSetUp() + { + _logger.debug("public void threadSetUp(): called"); + + try + { + // Call the set up method in the super class. This creates a PingClient pinger. + super.threadSetUp(); + + // Create the chained message listener, only if it has not already been created. This is set up with the + // batch size property, to tell it what batch size to output results on. A synchronized block is used to + // ensure that only one thread creates this. + synchronized (this) + { + if (batchedResultsListener == null) + { + int batchSize = Integer.parseInt(testParameters.getProperty(TEST_RESULTS_BATCH_SIZE_PROPNAME)); + batchedResultsListener = new BatchedResultsListener(batchSize); + } + } + + // Get the set up that the super class created. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Register the chained message listener on the pinger to do its asynchronous test timings from. + perThreadSetup._pingClient.setChainedMessageListener(batchedResultsListener); + } + catch (Exception e) + { + _logger.warn("There was an exception during per thread setup.", e); + } + } + + /** + * BatchedResultsListener is a {@link PingPongProducer.ChainedMessageListener} that can be attached to the + * pinger, in order to receive notifications about every message received and the number remaining to be + * received. Whenever the number remaining crosses a batch size boundary this results listener outputs + * a test timing for the actual number of messages received in the current batch. + */ + private class BatchedResultsListener implements PingPongProducer.ChainedMessageListener + { + /** The test results logging batch size. */ + int _batchSize; + + /** + * Creates a results listener on the specified batch size. + * + * @param batchSize The batch size to use. + */ + public BatchedResultsListener(int batchSize) + { + _batchSize = batchSize; + } + + /** + * This callback method is called from all of the pingers that this test creates. It uses the correlation id + * from the message to identify the timing controller for the test thread that was responsible for sending those + * messages. + * + * @param message The message. + * @param remainingCount The count of messages remaining to be received with a particular correlation id. + * + * @throws JMSException Any underlying JMSException is allowed to fall through. + */ + public void onMessage(Message message, int remainingCount, long latency) throws JMSException + { + // Check if a batch boundary has been crossed. + if ((remainingCount % _batchSize) == 0) + { + // Extract the correlation id from the message. + String correlationId = message.getJMSCorrelationID(); + + /*_logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount + + "): called on batch boundary for message id: " + correlationId + " with thread id: " + + Thread.currentThread().getId());*/ + + // Get the details for the correlation id and check that they are not null. They can become null + // if a test times out. + PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationId); + if (perCorrelationId != null) + { + // Get the timing controller and expected count for this correlation id. + TimingController tc = perCorrelationId._tc; + int expected = perCorrelationId._expectedCount; + + // Calculate how many messages were actually received in the last batch. This will be the batch size + // except where the number expected is not a multiple of the batch size and this is the first remaining + // count to cross a batch size boundary, in which case it will be the number expected modulo the batch + // size. + int receivedInBatch = ((expected - remainingCount) < _batchSize) ? (expected % _batchSize) : _batchSize; + + // Register a test result for the correlation id. + try + { + tc.completeTest(true, receivedInBatch); + } + catch (InterruptedException e) + { + // Ignore this. It means the test runner wants to stop as soon as possible. + _logger.warn("Got InterruptedException.", e); + } + } + // Else ignore, test timed out. Should log a fail here? + } + } + } + + /** + * Holds state specific to each correlation id, needed to output test results. This consists of the count of + * the total expected number of messages, and the timing controller for the thread sending those message ids. + */ + private static class PerCorrelationId + { + public int _expectedCount; + public TimingController _tc; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java new file mode 100644 index 0000000000..b9632eee4c --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java @@ -0,0 +1,107 @@ +/* + * + * 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.qpid.ping; + +import org.apache.log4j.Logger; + +import org.apache.qpid.requestreply.PingPongProducer; + +import javax.jms.Destination; + +import java.util.List; +import java.util.Properties; + +/** + * PingClient is a {@link PingPongProducer} that does not need a {@link org.apache.qpid.requestreply.PingPongBouncer} + * to send replies to its pings. It simply listens to its own ping destinations, rather than seperate reply queues. + * It is an all in one ping client, that produces and consumes its own pings. + * + *

    The constructor increments a count of the number of ping clients created. It is assumed that where many + * are created they will all be run in parallel and be active in sending and consuming pings at the same time. + * If the unique destinations flag is not set and a pub/sub ping cycle is being run, this means that they will all hear + * pings sent by each other. The expected number of pings received will therefore be multiplied up by the number of + * active ping clients. The {@link #getConsumersPerDestination()} method is used to supply this multiplier under these + * conditions. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Create a ping producer that listens to its own pings {@link PingPongProducer} + *
    Count the number of ping producers and produce multiplier for scaling up messages expected over topic pings. + *
    + */ +public class PingClient extends PingPongProducer +{ + /** Used for debugging. */ + private final Logger log = Logger.getLogger(PingClient.class); + + /** Used to count the number of ping clients created. */ + private static int _pingClientCount; + + /** + * Creates a ping producer with the specified parameters, of which there are many. See the class level comments + * for {@link PingPongProducer} for details. This constructor creates a connection to the broker and creates + * producer and consumer sessions on it, to send and recieve its pings and replies on. + * + * @param overrides Properties containing any desired overrides to the defaults. + * + * @throws Exception Any exceptions are allowed to fall through. + */ + public PingClient(Properties overrides) throws Exception + { + super(overrides); + + _pingClientCount++; + } + + /** + * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the + * effect of making this pinger listen to its own pings. + * + * @return The ping destinations. + */ + public List getReplyDestinations() + { + return _pingDestinations; + } + + /** + * Supplies the multiplier for the number of ping clients that will hear each ping when doing pub/sub pinging. + * + * @return The scaling up of the number of expected pub/sub pings. + */ + public int getConsumersPerDestination() + { + log.debug("public int getConsumersPerDestination(): called"); + + if (_isUnique) + { + log.debug(_noOfConsumers + " consumer per destination."); + + return _noOfConsumers; + } + else + { + log.debug((_pingClientCount * _noOfConsumers) + " consumers per destination."); + + return _pingClientCount * _noOfConsumers; + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java new file mode 100644 index 0000000000..0c8c19243a --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java @@ -0,0 +1,452 @@ +/* + * + * 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.qpid.ping; + +import org.apache.log4j.Logger; + +import org.apache.qpid.requestreply.PingPongProducer; +import org.apache.qpid.util.CommandLineParser; + +import org.apache.qpid.junit.extensions.util.MathUtils; +import org.apache.qpid.junit.extensions.util.ParsedProperties; + +import javax.jms.*; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * PingDurableClient is a variation of the {@link PingPongProducer} ping tool. Instead of sending its pings and + * receiving replies to them at the same time, this tool sends pings until it is signalled by some 'event' to stop + * sending. It then waits for another signal before it re-opens a fresh connection and attempts to receive all of the + * pings that it has succesfully sent. It is intended to be an interactive test that lets a user experiment with + * failure conditions when using durable messaging. + * + *

    The events that can stop it from sending are input from the user on the console, failure of its connection to + * the broker, completion of sending a specified number of messages, or expiry of a specified duration. In all cases + * it will do its best to clean up and close the connection before opening a fresh connection to receive the pings + * with. + * + *

    The event to re-connect and attempt to recieve the pings is input from the user on the console. + * + *

    This ping client inherits the configuration properties of its parent class ({@link PingPongProducer}) and + * additionally accepts the following parameters: + * + *

    + *
    Parameters
    Parameter Default Comments + *
    numMessages 100 The total number of messages to send. + *
    numMessagesToAction -1 The number of messages to send before taking a custom 'action'. + *
    duration 30S The length of time to ping for. (Format dDhHmMsS, for d days, h hours, + * m minutes and s seconds). + *
    + * + *

    This ping client also overrides some of the defaults of its parent class, to provide a reasonable set up + * when no parameters are specified. + * + *

    + *
    Parameters
    Parameter Default Comments + *
    uniqueDests false Prevents destination names being timestamped. + *
    transacted true Only makes sense to test with transactions. + *
    persistent true Only makes sense to test persistent. + *
    durableDests true Should use durable queues with persistent messages. + *
    commitBatchSize 10 + *
    rate 20 Total default test time is 5 seconds. + *
    + * + *

    When a number of messages or duration is specified, this ping client will ping until the first of those limits + * is reached. Reaching the limit will be interpreted as the first signal to stop sending, and the ping client will + * wait for the second signal before receiving its pings. + * + *

    This class provides a mechanism for extensions to add arbitrary actions, after a particular number of messages + * have been sent. When the number of messages equal the value set in the 'numMessagesToAction' property is method, + * the {@link #takeAction} method is called. By default this does nothing, but extensions of this class can provide + * custom behaviour with alternative implementations of this method (for example taking a backup). + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Send and receive pings. + *
    Accept user input to signal stop sending. + *
    Accept user input to signal start receiving. + *
    Provide feedback on pings sent versus pings received. + *
    Provide extension point for arbitrary action on a particular message count. + *
    + */ +public class PingDurableClient extends PingPongProducer implements ExceptionListener +{ + private static final Logger log = Logger.getLogger(PingDurableClient.class); + + public static final String NUM_MESSAGES_PROPNAME = "numMessages"; + public static final String NUM_MESSAGES_DEFAULT = "100"; + public static final String DURATION_PROPNAME = "duration"; + public static final String DURATION_DEFAULT = "30S"; + public static final String NUM_MESSAGES_TO_ACTION_PROPNAME = "numMessagesToAction"; + public static final String NUM_MESSAGES_TO_ACTION_DEFAULT = "-1"; + + /** The maximum length of time to wait whilst receiving pings before assuming that no more are coming. */ + private static final long TIME_OUT = 3000; + + static + { + defaults.setProperty(NUM_MESSAGES_PROPNAME, NUM_MESSAGES_DEFAULT); + defaults.setProperty(DURATION_PROPNAME, DURATION_DEFAULT); + defaults.setProperty(UNIQUE_DESTS_PROPNAME, "false"); + defaults.setProperty(TRANSACTED_PROPNAME, "true"); + defaults.setProperty(PERSISTENT_MODE_PROPNAME, "true"); + defaults.setProperty(TX_BATCH_SIZE_PROPNAME, "10"); + defaults.setProperty(RATE_PROPNAME, "20"); + defaults.setProperty(DURABLE_DESTS_PROPNAME, "true"); + defaults.setProperty(NUM_MESSAGES_TO_ACTION_PROPNAME, NUM_MESSAGES_TO_ACTION_DEFAULT); + } + + /** Specifies the number of pings to send, if larger than 0. 0 means send until told to stop. */ + private int numMessages; + + /** Holds the number of messages to send before taking triggering the action. */ + private int numMessagesToAction; + + /** Sepcifies how long to ping for, if larger than 0. 0 means send until told to stop. */ + private long duration; + + /** Used to indciate that this application should terminate. Set by the shutdown hook. */ + private boolean terminate = false; + + /** + * @throws Exception Any exceptions are allowed to fall through. + */ + public PingDurableClient(Properties overrides) throws Exception + { + super(overrides); + log.debug("public PingDurableClient(Properties overrides = " + overrides + "): called"); + + // Extract the additional configuration parameters. + ParsedProperties properties = new ParsedProperties(defaults); + properties.putAll(overrides); + + numMessages = properties.getPropertyAsInteger(NUM_MESSAGES_PROPNAME); + String durationSpec = properties.getProperty(DURATION_PROPNAME); + numMessagesToAction = properties.getPropertyAsInteger(NUM_MESSAGES_TO_ACTION_PROPNAME); + + if (durationSpec != null) + { + duration = MathUtils.parseDuration(durationSpec) * 1000000; + } + } + + /** + * Starts the ping/wait/receive process. + * + * @param args The command line arguments. + */ + public static void main(String[] args) + { + try + { + // Create a ping producer overriding its defaults with all options passed on the command line. + Properties options = + CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); + PingDurableClient pingProducer = new PingDurableClient(options); + + // Create a shutdown hook to terminate the ping-pong producer. + Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); + + // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. + // pingProducer.getConnection().setExceptionListener(pingProducer); + + // Run the test procedure. + int sent = pingProducer.send(); + pingProducer.closeConnection(); + pingProducer.waitForUser("Press return to begin receiving the pings."); + pingProducer.receive(sent); + + System.exit(0); + } + catch (Exception e) + { + System.err.println(e.getMessage()); + log.error("Top level handler caught execption.", e); + System.exit(1); + } + } + + /** + * Performs the main test procedure implemented by this ping client. See the class level comment for details. + */ + protected int send() throws Exception + { + log.debug("public void sendWaitReceive(): called"); + + log.debug("duration = " + duration); + log.debug("numMessages = " + numMessages); + + if (duration > 0) + { + System.out.println("Sending for up to " + (duration / 1000000000f) + " seconds."); + } + + if (_rate > 0) + { + System.out.println("Sending at " + _rate + " messages per second."); + } + + if (numMessages > 0) + { + System.out.println("Sending up to " + numMessages + " messages."); + } + + // Establish the connection and the message producer. + establishConnection(true, false); + _connection.start(); + + Message message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent); + + // Send pings until a terminating condition is received. + boolean endCondition = false; + int messagesSent = 0; + int messagesCommitted = 0; + int messagesNotCommitted = 0; + long start = System.nanoTime(); + + // Clear console in. + clearConsole(); + + while (!endCondition) + { + boolean committed = false; + + try + { + committed = sendMessage(messagesSent, message) && _transacted; + + messagesSent++; + messagesNotCommitted++; + + // Keep count of the number of messsages currently committed and pending commit. + if (committed) + { + log.debug("Adding " + messagesNotCommitted + " messages to the committed count."); + messagesCommitted += messagesNotCommitted; + messagesNotCommitted = 0; + + System.out.println("Commited: " + messagesCommitted); + } + } + catch (JMSException e) + { + log.debug("Got JMSException whilst sending."); + _publish = false; + } + + // Perform the arbitrary action if the number of messages sent has reached the right number. + if (messagesSent == numMessagesToAction) + { + System.out.println("At action point, Messages sent = " + messagesSent + ", Messages Committed = " + + messagesCommitted + ", Messages not Committed = " + messagesNotCommitted); + takeAction(); + } + + // Determine if the end condition has been met, based on the number of messages, time passed, errors on + // the connection or user input. + long now = System.nanoTime(); + + if ((duration != 0) && ((now - start) > duration)) + { + System.out.println("Send halted because duration expired."); + endCondition = true; + } + else if ((numMessages != 0) && (messagesSent >= numMessages)) + { + System.out.println("Send halted because # messages completed."); + endCondition = true; + } + else if (System.in.available() > 0) + { + System.out.println("Send halted by user input."); + endCondition = true; + + clearConsole(); + } + else if (!_publish) + { + System.out.println("Send halted by error on the connection."); + endCondition = true; + } + } + + log.debug("messagesSent = " + messagesSent); + log.debug("messagesCommitted = " + messagesCommitted); + log.debug("messagesNotCommitted = " + messagesNotCommitted); + + System.out.println("Messages sent: " + messagesSent + ", Messages Committed = " + messagesCommitted + + ", Messages not Committed = " + messagesNotCommitted); + + return messagesSent; + } + + protected void closeConnection() + { + // Clean up the connection. + try + { + close(); + } + catch (JMSException e) + { + log.debug("There was an error whilst closing the connection: " + e, e); + System.out.println("There was an error whilst closing the connection."); + + // Ignore as did best could manage to clean up. + } + } + + protected void receive(int messagesSent) throws Exception + { + // Re-establish the connection and the message consumer. + _queueJVMSequenceID = new AtomicInteger(); + _queueSharedID = new AtomicInteger(); + + establishConnection(false, true); + _consumer[0].setMessageListener(null); + _consumerConnection[0].start(); + + // Try to receive all of the pings that were successfully sent. + int messagesReceived = 0; + boolean endCondition = false; + + while (!endCondition) + { + // Message received = _consumer.receiveNoWait(); + Message received = _consumer[0].receive(TIME_OUT); + log.debug("received = " + received); + + if (received != null) + { + messagesReceived++; + } + + // Determine if the end condition has been met, based on the number of messages and time passed since last + // receiving a message. + if (received == null) + { + System.out.println("Timed out."); + endCondition = true; + } + else if (messagesReceived >= messagesSent) + { + System.out.println("Got all messages."); + endCondition = true; + } + } + + // Ensure messages received are committed. + if (_consTransacted) + { + try + { + _consumerSession[0].commit(); + System.out.println("Committed for all messages received."); + } + catch (JMSException e) + { + log.debug("Error during commit: " + e, e); + System.out.println("Error during commit."); + try + { + _consumerSession[0].rollback(); + System.out.println("Rolled back on all messages received."); + } + catch (JMSException e2) + { + log.debug("Error during rollback: " + e, e); + System.out.println("Error on roll back of all messages received."); + } + + } + } + + log.debug("messagesReceived = " + messagesReceived); + + System.out.println("Messages received: " + messagesReceived); + + // Clean up the connection. + close(); + } + + /** + * Clears any pending input from the console. + */ + private void clearConsole() + { + try + { + BufferedReader bis = new BufferedReader(new InputStreamReader(System.in)); + + // System.in.skip(System.in.available()); + while (bis.ready()) + { + bis.readLine(); + } + } + catch (IOException e) + { } + } + + /** + * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the + * effect of making this pinger listen to its own pings. + * + * @return The ping destinations. + */ + public List getReplyDestinations() + { + return _pingDestinations; + } + + /** + * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered with + * the runtime system as a shutdown hook. This shutdown hook sets an additional terminate flag, compared with the + * shutdown hook in {@link PingPongProducer}, because the publish flag is used to indicate that sending or receiving + * message should stop, not that the application should termiante. + * + * @return A shutdown hook for the ping loop. + */ + public Thread getShutdownHook() + { + return new Thread(new Runnable() + { + public void run() + { + stop(); + terminate = true; + } + }); + } + + /** + * Performs an aribtrary action once the 'numMesagesToAction' count is reached on sending messages. This default + * implementation does nothing. + */ + public void takeAction() + { } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java new file mode 100644 index 0000000000..215dbcefa3 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java @@ -0,0 +1,311 @@ +/* + * + * 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.qpid.ping; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.requestreply.PingPongProducer; + +import org.apache.qpid.junit.extensions.TimingController; +import org.apache.qpid.junit.extensions.TimingControllerAware; +import org.apache.qpid.junit.extensions.util.ParsedProperties; + +import javax.jms.JMSException; +import javax.jms.Message; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +/** + * PingLatencyTestPerf is a performance test that outputs multiple timings from its test method, using the timing + * controller interface supplied by the test runner from a seperate listener thread. It outputs round trip timings for + * individual ping messages rather than for how long a complete batch of messages took to process. It also differs from + * the {@link PingTestPerf} test that it extends because it can output timings as replies are received, rather than + * waiting until all expected replies are received. + * + *

    This test does not output timings for every single ping message, as when running at high volume, writing the test + * log for a vast number of messages would slow the testing down. Instead samples ping latency occasionally. The + * frequency of ping sampling is set using the {@link #TEST_RESULTS_BATCH_SIZE_PROPNAME} property, to override the + * default of every {@link #DEFAULT_TEST_RESULTS_BATCH_SIZE}. + * + *

    The size parameter logged for each individual ping is set to the size of the batch of messages that the + * individual timed ping was taken from, rather than 1 for a single message. This is so that the total throughput + * (messages / time) can be calculated in order to examine the relationship between throughput and latency. + * + *

    CRC Card
    Responsibilities Collaborations
    Send many ping + * messages and output timings for sampled individual pings.
    + */ +public class PingLatencyTestPerf extends PingTestPerf implements TimingControllerAware +{ + private static Logger _logger = Logger.getLogger(PingLatencyTestPerf.class); + + /** Holds the name of the property to get the test results logging batch size. */ + public static final String TEST_RESULTS_BATCH_SIZE_PROPNAME = "batchSize"; + + /** Holds the default test results logging batch size. */ + public static final int DEFAULT_TEST_RESULTS_BATCH_SIZE = 1000; + + /** Used to hold the timing controller passed from the test runner. */ + private TimingController _timingController; + + /** Used to generate unique correlation ids for each test run. */ + private AtomicLong corellationIdGenerator = new AtomicLong(); + + /** + * Holds test specifics by correlation id. This consists of the expected number of messages and the timing + * controler. + */ + private Map perCorrelationIds = + Collections.synchronizedMap(new HashMap()); + + /** Holds the batched results listener, that does logging on batch boundaries. */ + private BatchedResultsListener batchedResultsListener = null; + + /** + * Creates a new asynchronous ping performance test with the specified name. + * + * @param name The test name. + */ + public PingLatencyTestPerf(String name) + { + super(name); + + // Sets up the test parameters with defaults. + ParsedProperties.setSysPropertyIfNull(TEST_RESULTS_BATCH_SIZE_PROPNAME, + Integer.toString(DEFAULT_TEST_RESULTS_BATCH_SIZE)); + } + + /** Compile all the tests into a test suite. */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Ping Latency Tests"); + + // Run performance tests in read committed mode. + suite.addTest(new PingLatencyTestPerf("testPingLatency")); + + return suite; + } + + /** + * Accepts a timing controller from the test runner. + * + * @param timingController The timing controller to register mutliple timings with. + */ + public void setTimingController(TimingController timingController) + { + _timingController = timingController; + } + + /** + * Gets the timing controller passed in by the test runner. + * + * @return The timing controller passed in by the test runner. + */ + public TimingController getTimingController() + { + return _timingController; + } + + /** + * Sends the specified number of pings, asynchronously outputs timings on every batch boundary, and waits until all + * replies have been received or a time out occurs before exiting this method. + * + * @param numPings The number of pings to send. + */ + public void testPingLatency(int numPings) throws Exception + { + _logger.debug("public void testPingLatency(int numPings): called"); + + // Ensure that at least one ping was requeusted. + if (numPings == 0) + { + _logger.error("Number of pings requested was zero."); + } + + // Get the per thread test setup to run the test through. + PerThreadSetup perThreadSetup = threadSetup.get(); + PingClient pingClient = perThreadSetup._pingClient; + + // Advance the correlation id of messages to send, to make it unique for this run. + String messageCorrelationId = Long.toString(corellationIdGenerator.incrementAndGet()); + _logger.debug("messageCorrelationId = " + messageCorrelationId); + + // Initialize the count and timing controller for the new correlation id. + PerCorrelationId perCorrelationId = new PerCorrelationId(); + TimingController tc = getTimingController().getControllerForCurrentThread(); + perCorrelationId._tc = tc; + perCorrelationId._expectedCount = numPings; + perCorrelationIds.put(messageCorrelationId, perCorrelationId); + + // Attach the chained message listener to the ping producer to listen asynchronously for the replies to these + // messages. + pingClient.setChainedMessageListener(batchedResultsListener); + + // Generate a sample message of the specified size. + Message msg = + pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0), + testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), + testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); + + // Send the requested number of messages, and wait until they have all been received. + long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); + int numReplies = pingClient.pingAndWaitForReply(msg, numPings, timeout, null); + + // Check that all the replies were received and log a fail if they were not. + if (numReplies < numPings) + { + tc.completeTest(false, 0); + } + + // Remove the chained message listener from the ping producer. + pingClient.removeChainedMessageListener(); + + // Remove the expected count and timing controller for the message correlation id, to ensure they are cleaned up. + perCorrelationIds.remove(messageCorrelationId); + } + + /** Performs test fixture creation on a per thread basis. This will only be called once for each test thread. */ + public void threadSetUp() + { + _logger.debug("public void threadSetUp(): called"); + + try + { + // Call the set up method in the super class. This creates a PingClient pinger. + super.threadSetUp(); + + // Create the chained message listener, only if it has not already been created. This is set up with the + // batch size property, to tell it what batch size to output results on. A synchronized block is used to + // ensure that only one thread creates this. + synchronized (this) + { + if (batchedResultsListener == null) + { + int batchSize = Integer.parseInt(testParameters.getProperty(TEST_RESULTS_BATCH_SIZE_PROPNAME)); + batchedResultsListener = new BatchedResultsListener(batchSize); + } + } + + // Get the set up that the super class created. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Register the chained message listener on the pinger to do its asynchronous test timings from. + perThreadSetup._pingClient.setChainedMessageListener(batchedResultsListener); + } + catch (Exception e) + { + _logger.warn("There was an exception during per thread setup.", e); + } + } + + /** + * BatchedResultsListener is a {@link org.apache.qpid.requestreply.PingPongProducer.ChainedMessageListener} that can + * be attached to the pinger, in order to receive notifications about every message received and the number + * remaining to be received. Whenever the number remaining crosses a batch size boundary this results listener + * outputs a test timing for the actual number of messages received in the current batch. + */ + private class BatchedResultsListener implements PingPongProducer.ChainedMessageListener + { + /** The test results logging batch size. */ + int _batchSize; + private boolean _strictAMQP; + + /** + * Creates a results listener on the specified batch size. + * + * @param batchSize The batch size to use. + */ + public BatchedResultsListener(int batchSize) + { + _batchSize = batchSize; + _strictAMQP = + Boolean.parseBoolean(System.getProperties().getProperty(AMQSession.STRICT_AMQP, + AMQSession.STRICT_AMQP_DEFAULT)); + } + + /** + * This callback method is called from all of the pingers that this test creates. It uses the correlation id + * from the message to identify the timing controller for the test thread that was responsible for sending those + * messages. + * + * @param message The message. + * @param remainingCount The count of messages remaining to be received with a particular correlation id. + * + * @throws javax.jms.JMSException Any underlying JMSException is allowed to fall through. + */ + public void onMessage(Message message, int remainingCount, long latency) throws JMSException + { + _logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount + "): called"); + + // Check if a batch boundary has been crossed. + if ((remainingCount % _batchSize) == 0) + { + // Extract the correlation id from the message. + String correlationId = message.getJMSCorrelationID(); + + // Get the details for the correlation id and check that they are not null. They can become null + // if a test times out. + PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationId); + if (perCorrelationId != null) + { + // Get the timing controller and expected count for this correlation id. + TimingController tc = perCorrelationId._tc; + int expected = perCorrelationId._expectedCount; + + // Calculate how many messages were actually received in the last batch. This will be the batch size + // except where the number expected is not a multiple of the batch size and this is the first remaining + // count to cross a batch size boundary, in which case it will be the number expected modulo the batch + // size. + int receivedInBatch = ((expected - remainingCount) < _batchSize) ? (expected % _batchSize) : _batchSize; + + // Register a test result for the correlation id. + try + { + tc.completeTest(true, receivedInBatch, latency); + } + catch (InterruptedException e) + { + // Ignore this. It means the test runner wants to stop as soon as possible. + _logger.warn("Got InterruptedException.", e); + } + } + // Else ignore, test timed out. Should log a fail here? + } + } + } + + /** + * Holds state specific to each correlation id, needed to output test results. This consists of the count of the + * total expected number of messages, and the timing controller for the thread sending those message ids. + */ + private static class PerCorrelationId + { + public int _expectedCount; + public TimingController _tc; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java new file mode 100644 index 0000000000..2879f0c322 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java @@ -0,0 +1,93 @@ +/* + * + * 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.qpid.ping; + +import java.util.Properties; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.ObjectMessage; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.util.CommandLineParser; + +/** + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    + */ +public class PingSendOnlyClient extends PingDurableClient +{ + private static final Logger log = Logger.getLogger(PingSendOnlyClient.class); + + public PingSendOnlyClient(Properties overrides) throws Exception + { + super(overrides); + } + + /** + * Starts the ping/wait/receive process. + * + * @param args The command line arguments. + */ + public static void main(String[] args) + { + try + { + // Create a ping producer overriding its defaults with all options passed on the command line. + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); + PingSendOnlyClient pingProducer = new PingSendOnlyClient(options); + + // Create a shutdown hook to terminate the ping-pong producer. + Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); + + // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. + // pingProducer.getConnection().setExceptionListener(pingProducer); + + // Run the test procedure. + int sent = pingProducer.send(); + pingProducer.waitForUser("Press return to close connection and quit."); + pingProducer.closeConnection(); + + System.exit(0); + } + catch (Exception e) + { + System.err.println(e.getMessage()); + log.error("Top level handler caught execption.", e); + System.exit(1); + } + } + + public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException + { + Message msg = TestMessageFactory.newTextMessage(_producerSession, messageSize); + + // Timestamp the message in nanoseconds. + msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); + + return msg; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java new file mode 100644 index 0000000000..fb071a87fe --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java @@ -0,0 +1,196 @@ +/* + * + * 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.qpid.ping; + +import junit.framework.Assert; +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +import org.apache.qpid.requestreply.PingPongProducer; + +import org.apache.qpid.junit.extensions.AsymptoticTestCase; +import org.apache.qpid.junit.extensions.TestThreadAware; +import org.apache.qpid.junit.extensions.util.ParsedProperties; +import org.apache.qpid.junit.extensions.util.TestContextProperties; + +import javax.jms.*; + +/** + * PingTestPerf is a ping test, that has been written with the intention of being scaled up to run many times + * simultaneously to simluate many clients/producers/connections. + * + *

    A single run of the test using the default JUnit test runner will result in the sending and timing of a single + * full round trip ping. This test may be scaled up using a suitable JUnit test runner. + * + *

    The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a + * temporary queue for replies. This setup is only established once for all the test repeats/threads that may be run, + * except if the connection is lost in which case an attempt to re-establish the setup is made. + * + *

    The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that + * is the name of the temporary queue, fires off a message on the original queue and waits for a response on the + * temporary queue. + * + *

    Configurable test properties: message size, transacted or not, persistent or not. Broker connection details. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    + */ +public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware +{ + private static Logger _logger = Logger.getLogger(PingTestPerf.class); + + /** Thread local to hold the per-thread test setup fields. */ + ThreadLocal threadSetup = new ThreadLocal(); + + /** Holds a property reader to extract the test parameters from. */ + protected ParsedProperties testParameters = + TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/); + + public PingTestPerf(String name) + { + super(name); + + _logger.debug("testParameters = " + testParameters); + } + + /** + * Compile all the tests into a test suite. + * @return The test method testPingOk. + */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Ping Performance Tests"); + + // Run performance tests in read committed mode. + suite.addTest(new PingTestPerf("testPingOk")); + + return suite; + } + + public void testPingOk(int numPings) throws Exception + { + if (numPings == 0) + { + Assert.fail("Number of pings requested was zero."); + } + + // Get the per thread test setup to run the test through. + PerThreadSetup perThreadSetup = threadSetup.get(); + + if (perThreadSetup == null) + { + Assert.fail("Could not get per thread test setup, it was null."); + } + + // Generate a sample message. This message is already time stamped and has its reply-to destination set. + Message msg = + perThreadSetup._pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0), + testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), + testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); + + // start the test + long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); + int numReplies = perThreadSetup._pingClient.pingAndWaitForReply(msg, numPings, timeout, null); + + // Fail the test if the timeout was exceeded. + if (numReplies != perThreadSetup._pingClient.getExpectedNumPings(numPings)) + { + Assert.fail("The ping timed out after " + timeout + " ms. Messages Sent = " + numPings + ", MessagesReceived = " + + numReplies); + } + } + + /** + * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. + */ + public void threadSetUp() + { + _logger.debug("public void threadSetUp(): called"); + + try + { + PerThreadSetup perThreadSetup = new PerThreadSetup(); + + // This is synchronized because there is a race condition, which causes one connection to sleep if + // all threads try to create connection concurrently. + synchronized (this) + { + // Establish a client to ping a Destination and listen the reply back from same Destination + perThreadSetup._pingClient = new PingClient(testParameters); + perThreadSetup._pingClient.establishConnection(true, true); + } + // Start the client connection + perThreadSetup._pingClient.start(); + + // Attach the per-thread set to the thread. + threadSetup.set(perThreadSetup); + } + catch (Exception e) + { + _logger.warn("There was an exception during per thread setup.", e); + } + } + + /** + * Performs test fixture clean + */ + public void threadTearDown() + { + _logger.debug("public void threadTearDown(): called"); + + try + { + // Get the per thread test fixture. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Close the pingers so that it cleans up its connection cleanly. + synchronized (this) + { + if ((perThreadSetup != null) && (perThreadSetup._pingClient != null)) + { + perThreadSetup._pingClient.close(); + } + } + } + catch (JMSException e) + { + _logger.warn("There was an exception during per thread tear down."); + } + finally + { + // Ensure the per thread fixture is reclaimed. + threadSetup.remove(); + } + } + + protected static class PerThreadSetup + { + /** + * Holds the test ping client. + */ + protected PingClient _pingClient; + protected String _correlationId; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java new file mode 100644 index 0000000000..0712557383 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -0,0 +1,453 @@ +/* + * + * 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.qpid.requestreply; + +import java.io.IOException; +import java.net.InetAddress; +import java.text.SimpleDateFormat; +import java.util.Date; + +import javax.jms.*; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.jms.ConnectionListener; +import org.apache.qpid.jms.Session; +import org.apache.qpid.topic.Config; +import org.apache.qpid.exchange.ExchangeDefaults; + +/** + * PingPongBouncer is a message listener the bounces back messages to their reply to destination. This is used to return + * ping messages generated by {@link org.apache.qpid.requestreply.PingPongProducer} but could be used for other purposes + * too. + * + *

    The correlation id from the received message is extracted, and placed into the reply as the correlation id. Messages + * are bounced back to their reply-to destination. The original sender of the message has the option to use either a unique + * temporary queue or the correlation id to correlate the original message to the reply. + * + *

    There is a verbose mode flag which causes information about each ping to be output to the console + * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should + * be disabled for real timing tests as writing to the console will slow things down. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Bounce back messages to their reply to destination. + *
    Provide command line invocation to start the bounce back on a configurable broker url. + *
    + * + * @todo Replace the command line parsing with a neater tool. + * + * @todo Make verbose accept a number of messages, only prints to console every X messages. + */ +public class PingPongBouncer implements MessageListener +{ + private static final Logger _logger = Logger.getLogger(PingPongBouncer.class); + + /** The default prefetch size for the message consumer. */ + private static final int PREFETCH = 1; + + /** The default no local flag for the message consumer. */ + private static final boolean NO_LOCAL = true; + + private static final String DEFAULT_DESTINATION_NAME = "ping"; + + /** The default exclusive flag for the message consumer. */ + private static final boolean EXCLUSIVE = false; + + /** A convenient formatter to use when time stamping output. */ + protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); + + /** Used to indicate that the reply generator should log timing info to the console (logger info level). */ + private boolean _verbose = false; + + /** Determines whether this bounce back client bounces back messages persistently. */ + private boolean _persistent = false; + + private Destination _consumerDestination; + + /** Keeps track of the response destination of the previous message for the last reply to producer cache. */ + private Destination _lastResponseDest; + + /** The producer for sending replies with. */ + private MessageProducer _replyProducer; + + /** The consumer controlSession. */ + private Session _consumerSession; + + /** The producer controlSession. */ + private Session _producerSession; + + /** Holds the connection to the broker. */ + private AMQConnection _connection; + + /** Flag used to indicate if this is a point to point or pub/sub ping client. */ + private boolean _isPubSub = false; + + /** + * This flag is used to indicate that the user should be prompted to kill a broker, in order to test + * failover, immediately before committing a transaction. + */ + protected boolean _failBeforeCommit = false; + + /** + * This flag is used to indicate that the user should be prompted to a kill a broker, in order to test + * failover, immediate after committing a transaction. + */ + protected boolean _failAfterCommit = false; + + /** + * Creates a PingPongBouncer on the specified producer and consumer sessions. + * + * @param brokerDetails The addresses of the brokers to connect to. + * @param username The broker username. + * @param password The broker password. + * @param virtualpath The virtual host name within the broker. + * @param destinationName The name of the queue to receive pings on + * (or root of the queue name where many queues are generated). + * @param persistent A flag to indicate that persistent message should be used. + * @param transacted A flag to indicate that pings should be sent within transactions. + * @param selector A message selector to filter received pings with. + * @param verbose A flag to indicate that message timings should be sent to the console. + * + * @throws Exception All underlying exceptions allowed to fall through. This is only test code... + */ + public PingPongBouncer(String brokerDetails, String username, String password, String virtualpath, + String destinationName, boolean persistent, boolean transacted, String selector, boolean verbose, + boolean pubsub) throws Exception + { + // Create a client id to uniquely identify this client. + InetAddress address = InetAddress.getLocalHost(); + String clientId = address.getHostName() + System.currentTimeMillis(); + _verbose = verbose; + _persistent = persistent; + setPubSub(pubsub); + // Connect to the broker. + setConnection(new AMQConnection(brokerDetails, username, password, clientId, virtualpath)); + _logger.info("Connected with URL:" + getConnection().toURL()); + + // Set up the failover notifier. + getConnection().setConnectionListener(new FailoverNotifier()); + + // Create a controlSession to listen for messages on and one to send replies on, transactional depending on the + // command line option. + _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + + // Create the queue to listen for message on. + createConsumerDestination(destinationName); + MessageConsumer consumer = + _consumerSession.createConsumer(_consumerDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); + + // Create a producer for the replies, without a default destination. + _replyProducer = _producerSession.createProducer(null); + _replyProducer.setDisableMessageTimestamp(true); + _replyProducer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + // Set this up to listen for messages on the queue. + consumer.setMessageListener(this); + } + + /** + * Starts a stand alone ping-pong client running in verbose mode. + * + * @param args + */ + public static void main(String[] args) throws Exception + { + System.out.println("Starting..."); + + // Display help on the command line. + if (args.length == 0) + { + _logger.info("Running test with default values..."); + //usage(); + //System.exit(0); + } + + // Extract all command line parameters. + Config config = new Config(); + config.setOptions(args); + String brokerDetails = config.getHost() + ":" + config.getPort(); + String virtualpath = "test"; + String destinationName = config.getDestination(); + if (destinationName == null) + { + destinationName = DEFAULT_DESTINATION_NAME; + } + + String selector = config.getSelector(); + boolean transacted = config.isTransacted(); + boolean persistent = config.usePersistentMessages(); + boolean pubsub = config.isPubSub(); + boolean verbose = true; + + //String selector = null; + + // Instantiate the ping pong client with the command line options and start it running. + PingPongBouncer pingBouncer = + new PingPongBouncer(brokerDetails, "guest", "guest", virtualpath, destinationName, persistent, transacted, + selector, verbose, pubsub); + pingBouncer.getConnection().start(); + + System.out.println("Waiting..."); + } + + private static void usage() + { + System.err.println("Usage: PingPongBouncer \n" + "-host : broker host\n" + "-port : broker port\n" + + "-destinationname : queue/topic name\n" + "-transacted : (true/false). Default is false\n" + + "-persistent : (true/false). Default is false\n" + + "-pubsub : (true/false). Default is false\n" + "-selector : selector string\n"); + } + + /** + * This is a callback method that is notified of all messages for which this has been registered as a message + * listener on a message consumer. It sends a reply (pong) to all messages it receieves on the reply to + * destination of the message. + * + * @param message The message that triggered this callback. + */ + public void onMessage(Message message) + { + try + { + String messageCorrelationId = message.getJMSCorrelationID(); + if (_verbose) + { + _logger.info(timestampFormatter.format(new Date()) + ": Got ping with correlation id, " + + messageCorrelationId); + } + + // Get the reply to destination from the message and check it is set. + Destination responseDest = message.getJMSReplyTo(); + + if (responseDest == null) + { + _logger.debug("Cannot send reply because reply-to destination is null."); + + return; + } + + // Spew out some timing information if verbose mode is on. + if (_verbose) + { + Long timestamp = message.getLongProperty("timestamp"); + + if (timestamp != null) + { + long diff = System.currentTimeMillis() - timestamp; + _logger.info("Time to bounce point: " + diff); + } + } + + // Correlate the reply to the original. + message.setJMSCorrelationID(messageCorrelationId); + + // Send the receieved message as the pong reply. + _replyProducer.send(responseDest, message); + + if (_verbose) + { + _logger.info(timestampFormatter.format(new Date()) + ": Sent reply with correlation id, " + + messageCorrelationId); + } + + // Commit the transaction if running in transactional mode. + commitTx(_producerSession); + } + catch (JMSException e) + { + _logger.debug("There was a JMSException: " + e.getMessage(), e); + } + } + + /** + * Gets the underlying connection that this ping client is running on. + * + * @return The underlying connection that this ping client is running on. + */ + public AMQConnection getConnection() + { + return _connection; + } + + /** + * Sets the connection that this ping client is using. + * + * @param connection The ping connection. + */ + public void setConnection(AMQConnection connection) + { + this._connection = connection; + } + + /** + * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic. + * + * @param pubsub true if this client is pinging a topic, false if it is pinging a queue. + */ + public void setPubSub(boolean pubsub) + { + _isPubSub = pubsub; + } + + /** + * Checks whether this client is a p2p or pub/sub ping client. + * + * @return true if this client is pinging a topic, false if it is pinging a queue. + */ + public boolean isPubSub() + { + return _isPubSub; + } + + /** + * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not + * a transactional controlSession, this method does nothing. + * + *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the + * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker + * after the commit is applied. + * + * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + */ + protected void commitTx(Session session) throws JMSException + { + if (session.getTransacted()) + { + try + { + if (_failBeforeCommit) + { + _logger.debug("Failing Before Commit"); + doFailover(); + } + + session.commit(); + + if (_failAfterCommit) + { + _logger.debug("Failing After Commit"); + doFailover(); + } + + _logger.debug("Session Commited."); + } + catch (JMSException e) + { + _logger.trace("JMSException on commit:" + e.getMessage(), e); + + try + { + session.rollback(); + _logger.debug("Message rolled back."); + } + catch (JMSException jmse) + { + _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); + + // Both commit and rollback failed. Throw the rollback exception. + throw jmse; + } + } + } + } + + /** + * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + * + * @param broker The name of the broker to terminate. + */ + protected void doFailover(String broker) + { + System.out.println("Kill Broker " + broker + " now."); + try + { + System.in.read(); + } + catch (IOException e) + { } + + System.out.println("Continuing."); + } + + /** + * Prompts the user to terminate the broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + */ + protected void doFailover() + { + System.out.println("Kill Broker now."); + try + { + System.in.read(); + } + catch (IOException e) + { } + + System.out.println("Continuing."); + + } + + private void createConsumerDestination(String name) + { + if (isPubSub()) + { + _consumerDestination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, name); + } + else + { + _consumerDestination = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, name); + } + } + + /** + * A connection listener that logs out any failover complete events. Could do more interesting things with this + * at some point... + */ + public static class FailoverNotifier implements ConnectionListener + { + public void bytesSent(long count) + { } + + public void bytesReceived(long count) + { } + + public boolean preFailover(boolean redirect) + { + return true; + } + + public boolean preResubscribe() + { + return true; + } + + public void failoverComplete() + { + _logger.info("App got failover complete callback."); + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java new file mode 100644 index 0000000000..f328675488 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -0,0 +1,1720 @@ +/* + * + * 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.qpid.requestreply; + +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; + +import org.apache.qpid.test.framework.TestUtils; + +import org.apache.qpid.junit.extensions.BatchedThrottle; +import org.apache.qpid.junit.extensions.Throttle; +import org.apache.qpid.junit.extensions.util.CommandLineParser; +import org.apache.qpid.junit.extensions.util.ParsedProperties; + +import javax.jms.*; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import java.io.*; +import java.net.InetAddress; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * PingPongProducer is a client that sends test messages, and waits for replies to these messages. The replies may + * either be generated by another client (see {@link PingPongBouncer}, or an extension of it may be used that listens + * to its own messages and does not send replies (see {@link org.apache.qpid.ping.PingClient}). The intention of ping + * pong producer is that it is a swiss-army knife test client that makes almost every aspect of its behaviour + * configurable. + * + *

    The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. This + * means that this class has to do some work to correlate pings with pongs; it expectes the original message correlation + * id in the ping to be bounced back in the reply correlation id. + * + *

    This ping tool accepts a vast number of configuration options, all of which are passed in to the constructor. It + * can ping topics or queues; ping multiple destinations; do persistent pings; send messages of any size; do pings within + * transactions; control the number of pings to send in each transaction; limit its sending rate; and perform failover + * testing. A complete list of accepted parameters, default values and comments on their usage is provided here: + * + *

    + *
    Parameters
    Parameter Default Comments + *
    messageSize 0 Message size in bytes. Not including any headers. + *
    destinationName ping The root name to use to generate destination names to ping. + *
    persistent false Determines whether peristent delivery is used. + *
    transacted false Determines whether messages are sent/received in transactions. + *
    broker tcp://localhost:5672 Determines the broker to connect to. + *
    virtualHost test Determines the virtual host to send all ping over. + *
    rate 0 The maximum rate (in hertz) to send messages at. 0 means no limit. + *
    verbose false The verbose flag for debugging. Prints to console on every message. + *
    pubsub false Whether to ping topics or queues. Uses p2p by default. + *
    failAfterCommit false Whether to prompt user to kill broker after a commit batch. + *
    failBeforeCommit false Whether to prompt user to kill broker before a commit batch. + *
    failAfterSend false Whether to prompt user to kill broker after a send. + *
    failBeforeSend false Whether to prompt user to kill broker before a send. + *
    failOnce true Whether to prompt for failover only once. + *
    username guest The username to access the broker with. + *
    password guest The password to access the broker with. + *
    selector null Not used. Defines a message selector to filter pings with. + *
    destinationCount 1 The number of destinations to send pings to. + *
    numConsumers 1 The number of consumers on each destination. + *
    timeout 30000 In milliseconds. The timeout to stop waiting for replies. + *
    commitBatchSize 1 The number of messages per transaction in transactional mode. + *
    uniqueDests true Whether each receivers only listens to one ping destination or all. + *
    durableDests false Whether or not durable destinations are used. + *
    ackMode AUTO_ACK The message acknowledgement mode. Possible values are: + * 0 - SESSION_TRANSACTED + * 1 - AUTO_ACKNOWLEDGE + * 2 - CLIENT_ACKNOWLEDGE + * 3 - DUPS_OK_ACKNOWLEDGE + * 257 - NO_ACKNOWLEDGE + * 258 - PRE_ACKNOWLEDGE + *
    consTransacted false Whether or not consumers use transactions. Defaults to the same value + * as the 'transacted' option if not seperately defined. + *
    consAckMode AUTO_ACK The message acknowledgement mode for consumers. Defaults to the same + * value as 'ackMode' if not seperately defined. + *
    maxPending 0 The maximum size in bytes, of messages sent but not yet received. + * Limits the volume of messages currently buffered on the client + * or broker. Can help scale test clients by limiting amount of buffered + * data to avoid out of memory errors. + *
    + * + *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop + * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so by + * starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is also + * registered to terminate the ping-pong loop cleanly. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Provide a ping and wait for all responses cycle. + *
    Provide command line invocation to loop the ping cycle on a configurable broker url. + *
    + * + * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock pair. + * Obtain read lock on all messages, before decrementing the message count. At the end of the on message method add a + * block that obtains the write lock for the very last message, releases any waiting producer. Means that the last + * message waits until all other messages have been handled before releasing producers but allows messages to be + * processed concurrently, unlike the current synchronized block. + */ +public class PingPongProducer implements Runnable, ExceptionListener +{ + /** Used for debugging. */ + private static final Logger log = Logger.getLogger(PingPongProducer.class); + + /** Holds the name of the property to determine whether of not client id is overridden at connection time. */ + public static final String OVERRIDE_CLIENT_ID_PROPNAME = "overrideClientId"; + + /** Holds the default value of the override client id flag. */ + public static final String OVERRIDE_CLIENT_ID_DEAFULT = "false"; + + /** Holds the name of the property to define the JNDI factory name with. */ + public static final String FACTORY_NAME_PROPNAME = "factoryName"; + + /** Holds the default JNDI name of the connection factory. */ + public static final String FACTORY_NAME_DEAFULT = "local"; + + /** Holds the name of the property to set the JNDI initial context properties with. */ + public static final String FILE_PROPERTIES_PROPNAME = "properties"; + + /** Holds the default file name of the JNDI initial context properties. */ + public static final String FILE_PROPERTIES_DEAFULT = "perftests.properties"; + + /** Holds the name of the property to get the test message size from. */ + public static final String MESSAGE_SIZE_PROPNAME = "messageSize"; + + /** Used to set up a default message size. */ + public static final int MESSAGE_SIZE_DEAFULT = 0; + + /** Holds the name of the property to get the ping queue name from. */ + public static final String PING_QUEUE_NAME_PROPNAME = "destinationName"; + + /** Holds the name of the default destination to send pings on. */ + public static final String PING_QUEUE_NAME_DEFAULT = "ping"; + + /** Holds the name of the property to get the queue name postfix from. */ + public static final String QUEUE_NAME_POSTFIX_PROPNAME = "queueNamePostfix"; + + /** Holds the default queue name postfix value. */ + public static final String QUEUE_NAME_POSTFIX_DEFAULT = ""; + + /** Holds the name of the property to get the test delivery mode from. */ + public static final String PERSISTENT_MODE_PROPNAME = "persistent"; + + /** Holds the message delivery mode to use for the test. */ + public static final boolean PERSISTENT_MODE_DEFAULT = false; + + /** Holds the name of the property to get the test transactional mode from. */ + public static final String TRANSACTED_PROPNAME = "transacted"; + + /** Holds the transactional mode to use for the test. */ + public static final boolean TRANSACTED_DEFAULT = false; + + /** Holds the name of the property to get the test consumer transacted mode from. */ + public static final String CONSUMER_TRANSACTED_PROPNAME = "consTransacted"; + + /** Holds the consumer transactional mode default setting. */ + public static final boolean CONSUMER_TRANSACTED_DEFAULT = false; + + /** Holds the name of the property to get the test broker url from. */ + public static final String BROKER_PROPNAME = "broker"; + + /** Holds the default broker url for the test. */ + public static final String BROKER_DEFAULT = "tcp://localhost:5672"; + + /** Holds the name of the property to get the test broker virtual path. */ + public static final String VIRTUAL_HOST_PROPNAME = "virtualHost"; + + /** Holds the default virtual path for the test. */ + public static final String VIRTUAL_HOST_DEFAULT = ""; + + /** Holds the name of the property to get the message rate from. */ + public static final String RATE_PROPNAME = "rate"; + + /** Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. */ + public static final int RATE_DEFAULT = 0; + + /** Holds the name of the property to get the verbose mode proeprty from. */ + public static final String VERBOSE_PROPNAME = "verbose"; + + /** Holds the default verbose mode. */ + public static final boolean VERBOSE_DEFAULT = false; + + /** Holds the name of the property to get the p2p or pub/sub messaging mode from. */ + public static final String PUBSUB_PROPNAME = "pubsub"; + + /** Holds the pub/sub mode default, true means ping a topic, false means ping a queue. */ + public static final boolean PUBSUB_DEFAULT = false; + + /** Holds the name of the property to get the fail after commit flag from. */ + public static final String FAIL_AFTER_COMMIT_PROPNAME = "failAfterCommit"; + + /** Holds the default failover after commit test flag. */ + public static final boolean FAIL_AFTER_COMMIT_DEFAULT = false; + + /** Holds the name of the proeprty to get the fail before commit flag from. */ + public static final String FAIL_BEFORE_COMMIT_PROPNAME = "failBeforeCommit"; + + /** Holds the default failover before commit test flag. */ + public static final boolean FAIL_BEFORE_COMMIT_DEFAULT = false; + + /** Holds the name of the proeprty to get the fail after send flag from. */ + public static final String FAIL_AFTER_SEND_PROPNAME = "failAfterSend"; + + /** Holds the default failover after send test flag. */ + public static final boolean FAIL_AFTER_SEND_DEFAULT = false; + + /** Holds the name of the property to get the fail before send flag from. */ + public static final String FAIL_BEFORE_SEND_PROPNAME = "failBeforeSend"; + + /** Holds the default failover before send test flag. */ + public static final boolean FAIL_BEFORE_SEND_DEFAULT = false; + + /** Holds the name of the property to get the fail once flag from. */ + public static final String FAIL_ONCE_PROPNAME = "failOnce"; + + /** The default failover once flag, true means only do one failover, false means failover on every commit cycle. */ + public static final boolean FAIL_ONCE_DEFAULT = true; + + /** Holds the name of the property to get the broker access username from. */ + public static final String USERNAME_PROPNAME = "username"; + + /** Holds the default broker log on username. */ + public static final String USERNAME_DEFAULT = "guest"; + + /** Holds the name of the property to get the broker access password from. */ + public static final String PASSWORD_PROPNAME = "password"; + + /** Holds the default broker log on password. */ + public static final String PASSWORD_DEFAULT = "guest"; + + /** Holds the name of the proeprty to get the. */ + public static final String SELECTOR_PROPNAME = "selector"; + + /** Holds the default message selector. */ + public static final String SELECTOR_DEFAULT = ""; + + /** Holds the name of the property to get the destination count from. */ + public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; + + /** Defines the default number of destinations to ping. */ + public static final int DESTINATION_COUNT_DEFAULT = 1; + + /** Holds the name of the property to get the number of consumers per destination from. */ + public static final String NUM_CONSUMERS_PROPNAME = "numConsumers"; + + /** Defines the default number consumers per destination. */ + public static final int NUM_CONSUMERS_DEFAULT = 1; + + /** Holds the name of the property to get the waiting timeout for response messages. */ + public static final String TIMEOUT_PROPNAME = "timeout"; + + /** Default time to wait before assuming that a ping has timed out. */ + public static final long TIMEOUT_DEFAULT = 30000; + + /** Holds the name of the property to get the commit batch size from. */ + public static final String TX_BATCH_SIZE_PROPNAME = "commitBatchSize"; + + /** Defines the default number of pings to send in each transaction when running transactionally. */ + public static final int TX_BATCH_SIZE_DEFAULT = 1; + + /** Holds the name of the property to get the unique destinations flag from. */ + public static final String UNIQUE_DESTS_PROPNAME = "uniqueDests"; + + /** Defines the default value for the unique destinations property. */ + public static final boolean UNIQUE_DESTS_DEFAULT = true; + + /** Holds the name of the property to get the durable destinations flag from. */ + public static final String DURABLE_DESTS_PROPNAME = "durableDests"; + + /** Defines the default value of the durable destinations flag. */ + public static final boolean DURABLE_DESTS_DEFAULT = false; + + /** Holds the name of the proeprty to get the message acknowledgement mode from. */ + public static final String ACK_MODE_PROPNAME = "ackMode"; + + /** Defines the default message acknowledgement mode. */ + public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; + + /** Holds the name of the property to get the consumers message acknowledgement mode from. */ + public static final String CONSUMER_ACK_MODE_PROPNAME = "consAckMode"; + + /** Defines the default consumers message acknowledgement mode. */ + public static final int CONSUMER_ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; + + /** Holds the name of the property to get the maximum pending message size setting from. */ + public static final String MAX_PENDING_PROPNAME = "maxPending"; + + /** Defines the default value for the maximum pending message size setting. 0 means no limit. */ + public static final int MAX_PENDING_DEFAULT = 0; + + /** Defines the default prefetch size to use when consuming messages. */ + public static final int PREFETCH_DEFAULT = 100; + + /** Defines the default value of the no local flag to use when consuming messages. */ + public static final boolean NO_LOCAL_DEFAULT = false; + + /** Defines the default value of the exclusive flag to use when consuming messages. */ + public static final boolean EXCLUSIVE_DEFAULT = false; + + /** Holds the name of the property to store nanosecond timestamps in ping messages with. */ + public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp"; + + /** Holds the default configuration properties. */ + public static ParsedProperties defaults = new ParsedProperties(); + + static + { + defaults.setPropertyIfNull(OVERRIDE_CLIENT_ID_PROPNAME, OVERRIDE_CLIENT_ID_DEAFULT); + defaults.setPropertyIfNull(FILE_PROPERTIES_PROPNAME, FILE_PROPERTIES_DEAFULT); + defaults.setPropertyIfNull(FACTORY_NAME_PROPNAME, FACTORY_NAME_DEAFULT); + defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT); + defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT); + defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT); + defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT); + defaults.setPropertyIfNull(PING_QUEUE_NAME_PROPNAME, PING_QUEUE_NAME_DEFAULT); + defaults.setPropertyIfNull(QUEUE_NAME_POSTFIX_PROPNAME, QUEUE_NAME_POSTFIX_DEFAULT); + defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT); + defaults.setPropertyIfNull(TRANSACTED_PROPNAME, TRANSACTED_DEFAULT); + defaults.setPropertyIfNull(CONSUMER_TRANSACTED_PROPNAME, CONSUMER_TRANSACTED_DEFAULT); + defaults.setPropertyIfNull(PERSISTENT_MODE_PROPNAME, PERSISTENT_MODE_DEFAULT); + defaults.setPropertyIfNull(ACK_MODE_PROPNAME, ACK_MODE_DEFAULT); + defaults.setPropertyIfNull(CONSUMER_ACK_MODE_PROPNAME, CONSUMER_ACK_MODE_DEFAULT); + defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT); + defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT); + defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT); + defaults.setPropertyIfNull(UNIQUE_DESTS_PROPNAME, UNIQUE_DESTS_DEFAULT); + defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT); + defaults.setPropertyIfNull(FAIL_BEFORE_COMMIT_PROPNAME, FAIL_BEFORE_COMMIT_DEFAULT); + defaults.setPropertyIfNull(FAIL_AFTER_COMMIT_PROPNAME, FAIL_AFTER_COMMIT_DEFAULT); + defaults.setPropertyIfNull(FAIL_BEFORE_SEND_PROPNAME, FAIL_BEFORE_SEND_DEFAULT); + defaults.setPropertyIfNull(FAIL_AFTER_SEND_PROPNAME, FAIL_AFTER_SEND_DEFAULT); + defaults.setPropertyIfNull(FAIL_ONCE_PROPNAME, FAIL_ONCE_DEFAULT); + defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT); + defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT); + defaults.setPropertyIfNull(NUM_CONSUMERS_PROPNAME, NUM_CONSUMERS_DEFAULT); + defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT); + defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT); + defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT); + } + + /** Allows setting of client ID on the connection, rather than through the connection URL. */ + protected boolean _overrideClientId; + + /** Holds the JNDI name of the JMS connection factory. */ + protected String _factoryName; + + /** Holds the name of the properties file to configure JNDI with. */ + protected String _fileProperties; + + /** Holds the broker url. */ + protected String _brokerDetails; + + /** Holds the username to access the broker with. */ + protected String _username; + + /** Holds the password to access the broker with. */ + protected String _password; + + /** Holds the virtual host on the broker to run the tests through. */ + protected String _virtualpath; + + /** Holds the root name from which to generate test destination names. */ + protected String _destinationName; + + /** Holds the default queue name postfix value. */ + protected String _queueNamePostfix; + + /** Holds the message selector to filter the pings with. */ + protected String _selector; + + /** Holds the producers transactional mode flag. */ + protected boolean _transacted; + + /** Holds the consumers transactional mode flag. */ + protected boolean _consTransacted; + + /** Determines whether this producer sends persistent messages. */ + protected boolean _persistent; + + /** Holds the acknowledgement mode used for the producers. */ + protected int _ackMode; + + /** Holds the acknowledgement mode setting for the consumers. */ + protected int _consAckMode; + + /** Determines what size of messages this producer sends. */ + protected int _messageSize; + + /** Used to indicate that the ping loop should print out whenever it pings. */ + protected boolean _verbose; + + /** Flag used to indicate if this is a point to point or pub/sub ping client. */ + protected boolean _isPubSub; + + /** Flag used to indicate if the destinations should be unique client. */ + protected boolean _isUnique; + + /** Flag used to indicate that durable destination should be used. */ + protected boolean _isDurable; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ + protected boolean _failBeforeCommit; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ + protected boolean _failAfterCommit; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ + protected boolean _failBeforeSend; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ + protected boolean _failAfterSend; + + /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ + protected boolean _failOnce; + + /** Holds the number of sends that should be performed in every transaction when using transactions. */ + protected int _txBatchSize; + + /** Holds the number of destinations to ping. */ + protected int _noOfDestinations; + + /** Holds the number of consumers per destination. */ + protected int _noOfConsumers; + + /** Holds the maximum send rate in herz. */ + protected int _rate; + + /** + * Holds the size of the maximum amount of pending data that the client should buffer, sending is suspended + * if this limit is breached. + */ + protected int _maxPendingSize; + + /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ + private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); + + /** A source for providing sequential unqiue ids for instances of this class to be identifed with. */ + private static AtomicInteger _instanceIdGenerator = new AtomicInteger(0); + + /** Holds this instances unique id. */ + private int instanceId; + + /** + * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross multiple + * ping producers on the same JVM. + */ + private static Map perCorrelationIds = + Collections.synchronizedMap(new HashMap()); + + /** A convenient formatter to use when time stamping output. */ + protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); + + /** Holds the connection for the message producer. */ + protected Connection _connection; + + /** Holds the consumer connections. */ + protected Connection[] _consumerConnection; + + /** Holds the controlSession on which ping replies are received. */ + protected Session[] _consumerSession; + + /** Holds the producer controlSession, needed to create ping messages. */ + protected Session _producerSession; + + /** Holds the destination where the response messages will arrive. */ + protected Destination _replyDestination; + + /** Holds the set of destinations that this ping producer pings. */ + protected List _pingDestinations; + + /** Used to restrict the sending rate to a specified limit. */ + protected Throttle _rateLimiter; + + /** Holds a message listener that this message listener chains all its messages to. */ + protected ChainedMessageListener _chainedMessageListener = null; + + /** + * This id generator is used to generate ids to append to the queue name to ensure that queues can be unique when + * creating multiple ping producers in the same JVM. + */ + protected static AtomicInteger _queueJVMSequenceID = new AtomicInteger(); + + /** + * This id generator is used to generates ids that are only unique within this pinger. Creating multiple pingers + * on the same JVM using this id generator will allow them to ping on the same queues. + */ + protected AtomicInteger _queueSharedID = new AtomicInteger(); + + /** Used to tell the ping loop when to terminate, it only runs while this is true. */ + protected boolean _publish = true; + + /** Holds the message producer to send the pings through. */ + protected MessageProducer _producer; + + /** Holds the message consumer to receive the ping replies through. */ + protected MessageConsumer[] _consumer; + + /** The prompt to display when asking the user to kill the broker for failover testing. */ + private static final String KILL_BROKER_PROMPT = "Kill broker now, then press Return."; + + /** Holds the name for this test client to be identified to the broker with. */ + private String _clientID; + + /** Keeps count of the total messages sent purely for debugging purposes. */ + private static AtomicInteger numSent = new AtomicInteger(); + + /** + * Holds a monitor which is used to synchronize sender and receivers threads, where the sender has elected + * to wait until the number of unreceived message is reduced before continuing to send. This monitor is a + * fair SynchronousQueue becuase that provides fair scheduling, to ensure that all producer threads get an + * equal chance to produce messages. + */ + static final SynchronousQueue _sendPauseMonitor = new SynchronousQueue(true); + + /** Keeps a count of the number of message currently sent but not received. */ + static AtomicInteger _unreceived = new AtomicInteger(0); + + /** + * Creates a ping producer with the specified parameters, of which there are many. See the class level comments + * for details. This constructor creates a connection to the broker and creates producer and consumer sessions on + * it, to send and recieve its pings and replies on. + * + * @param overrides Properties containing any desired overrides to the defaults. + * + * @throws Exception Any exceptions are allowed to fall through. + */ + public PingPongProducer(Properties overrides) throws Exception + { + // log.debug("public PingPongProducer(Properties overrides = " + overrides + "): called"); + instanceId = _instanceIdGenerator.getAndIncrement(); + + // Create a set of parsed properties from the defaults overriden by the passed in values. + ParsedProperties properties = new ParsedProperties(defaults); + properties.putAll(overrides); + + // Extract the configuration properties to set the pinger up with. + _overrideClientId = properties.getPropertyAsBoolean(OVERRIDE_CLIENT_ID_PROPNAME); + _factoryName = properties.getProperty(FACTORY_NAME_PROPNAME); + _fileProperties = properties.getProperty(FILE_PROPERTIES_PROPNAME); + _brokerDetails = properties.getProperty(BROKER_PROPNAME); + _username = properties.getProperty(USERNAME_PROPNAME); + _password = properties.getProperty(PASSWORD_PROPNAME); + _virtualpath = properties.getProperty(VIRTUAL_HOST_PROPNAME); + _destinationName = properties.getProperty(PING_QUEUE_NAME_PROPNAME); + _queueNamePostfix = properties.getProperty(QUEUE_NAME_POSTFIX_PROPNAME); + _selector = properties.getProperty(SELECTOR_PROPNAME); + _transacted = properties.getPropertyAsBoolean(TRANSACTED_PROPNAME); + _consTransacted = properties.getPropertyAsBoolean(CONSUMER_TRANSACTED_PROPNAME); + _persistent = properties.getPropertyAsBoolean(PERSISTENT_MODE_PROPNAME); + _messageSize = properties.getPropertyAsInteger(MESSAGE_SIZE_PROPNAME); + _verbose = properties.getPropertyAsBoolean(VERBOSE_PROPNAME); + _failAfterCommit = properties.getPropertyAsBoolean(FAIL_AFTER_COMMIT_PROPNAME); + _failBeforeCommit = properties.getPropertyAsBoolean(FAIL_BEFORE_COMMIT_PROPNAME); + _failAfterSend = properties.getPropertyAsBoolean(FAIL_AFTER_SEND_PROPNAME); + _failBeforeSend = properties.getPropertyAsBoolean(FAIL_BEFORE_SEND_PROPNAME); + _failOnce = properties.getPropertyAsBoolean(FAIL_ONCE_PROPNAME); + _txBatchSize = properties.getPropertyAsInteger(TX_BATCH_SIZE_PROPNAME); + _noOfDestinations = properties.getPropertyAsInteger(DESTINATION_COUNT_PROPNAME); + _noOfConsumers = properties.getPropertyAsInteger(NUM_CONSUMERS_PROPNAME); + _rate = properties.getPropertyAsInteger(RATE_PROPNAME); + _isPubSub = properties.getPropertyAsBoolean(PUBSUB_PROPNAME); + _isUnique = properties.getPropertyAsBoolean(UNIQUE_DESTS_PROPNAME); + _isDurable = properties.getPropertyAsBoolean(DURABLE_DESTS_PROPNAME); + _ackMode = _transacted ? 0 : properties.getPropertyAsInteger(ACK_MODE_PROPNAME); + _consAckMode = _consTransacted ? 0 : properties.getPropertyAsInteger(CONSUMER_ACK_MODE_PROPNAME); + _maxPendingSize = properties.getPropertyAsInteger(MAX_PENDING_PROPNAME); + + // Check that one or more destinations were specified. + if (_noOfDestinations < 1) + { + throw new IllegalArgumentException("There must be at least one destination."); + } + + // Set up a throttle to control the send rate, if a rate > 0 is specified. + if (_rate > 0) + { + _rateLimiter = new BatchedThrottle(); + _rateLimiter.setRate(_rate); + } + + // Create the connection and message producers/consumers. + // establishConnection(true, true); + } + + /** + * Establishes a connection to the broker and creates message consumers and producers based on the parameters + * that this ping client was created with. + * + * @param producer Flag to indicate whether or not the producer should be set up. + * @param consumer Flag to indicate whether or not the consumers should be set up. + * + * @throws Exception Any exceptions are allowed to fall through. + */ + public void establishConnection(boolean producer, boolean consumer) throws Exception + { + // log.debug("public void establishConnection(): called"); + + // Generate a unique identifying name for this client, based on it ip address and the current time. + InetAddress address = InetAddress.getLocalHost(); + // _clientID = address.getHostName() + System.currentTimeMillis(); + _clientID = "perftest_" + instanceId; + + // Create a connection to the broker. + createConnection(_clientID); + + // Create transactional or non-transactional sessions, based on the command line arguments. + _producerSession = _connection.createSession(_transacted, _ackMode); + + _consumerSession = new Session[_noOfConsumers]; + + for (int i = 0; i < _noOfConsumers; i++) + { + _consumerSession[i] = _consumerConnection[i].createSession(_consTransacted, _consAckMode); + } + + // Create the destinations to send pings to and receive replies from. + _replyDestination = _consumerSession[0].createTemporaryQueue(); + createPingDestinations(_noOfDestinations, _selector, _destinationName, _isUnique, _isDurable); + + // Create the message producer only if instructed to. + if (producer) + { + createProducer(); + } + + // Create the message consumer only if instructed to. + if (consumer) + { + createReplyConsumers(getReplyDestinations(), _selector); + } + } + + /** + * Establishes a connection to the broker, based on the configuration parameters that this ping client was + * created with. + * + * @param clientID The clients identifier. + * + * @throws JMSException Underlying exceptions allowed to fall through. + * @throws NamingException Underlying exceptions allowed to fall through. + * @throws IOException Underlying exceptions allowed to fall through. + */ + protected void createConnection(String clientID) throws JMSException, NamingException, IOException + { + // _log.debug("protected void createConnection(String clientID = " + clientID + "): called"); + + // _log.debug("Creating a connection for the message producer."); + File propsFile = new File(_fileProperties); + InputStream is = new FileInputStream(propsFile); + Properties properties = new Properties(); + properties.load(is); + + Context context = new InitialContext(properties); + ConnectionFactory factory = (ConnectionFactory) context.lookup(_factoryName); + _connection = factory.createConnection(_username, _password); + + if (_overrideClientId) + { + _connection.setClientID(clientID); + } + + // _log.debug("Creating " + _noOfConsumers + " connections for the consumers."); + + _consumerConnection = new Connection[_noOfConsumers]; + + for (int i = 0; i < _noOfConsumers; i++) + { + _consumerConnection[i] = factory.createConnection(_username, _password); + // _consumerConnection[i].setClientID(clientID); + } + } + + /** + * Starts a ping-pong loop running from the command line. The bounce back client {@link PingPongBouncer} also needs + * to be started to bounce the pings back again. + * + * @param args The command line arguments. + */ + public static void main(String[] args) + { + try + { + Properties options = + CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); + + // Create a ping producer overriding its defaults with all options passed on the command line. + PingPongProducer pingProducer = new PingPongProducer(options); + pingProducer.establishConnection(true, true); + + // Start the ping producers dispatch thread running. + pingProducer._connection.start(); + + // Create a shutdown hook to terminate the ping-pong producer. + Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); + + // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. + pingProducer._connection.setExceptionListener(pingProducer); + + // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. + Thread pingThread = new Thread(pingProducer); + pingThread.run(); + pingThread.join(); + } + catch (Exception e) + { + System.err.println(e.getMessage()); + log.error("Top level handler caught execption.", e); + System.exit(1); + } + } + + /** + * Convenience method for a short pause. + * + * @param sleepTime The time in milliseconds to pause for. + */ + public static void pause(long sleepTime) + { + if (sleepTime > 0) + { + try + { + Thread.sleep(sleepTime); + } + catch (InterruptedException ie) + { } + } + } + + /** + * Gets all the reply destinations (to listen for replies on). In this case this will just be the single reply to + * destination of this pinger. + * + * @return The single reply to destination of this pinger, wrapped in a list. + */ + public List getReplyDestinations() + { + // log.debug("public List getReplyDestinations(): called"); + + List replyDestinations = new ArrayList(); + replyDestinations.add(_replyDestination); + + // log.debug("replyDestinations = " + replyDestinations); + + return replyDestinations; + } + + /** + * Creates the producer to send the pings on. This is created without a default destination. Its persistent delivery + * flag is set accoring the ping producer creation options. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + public void createProducer() throws JMSException + { + // log.debug("public void createProducer(): called"); + + _producer = (MessageProducer) _producerSession.createProducer(null); + _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + // log.debug("Created producer for " + (_persistent ? "persistent" : "non-persistent") + " messages."); + } + + /** + * Creates consumers for the specified number of destinations. The destinations themselves are also created by this + * method. + * + * @param noOfDestinations The number of destinations to create consumers for. + * @param selector The message selector to filter the consumers with. + * @param rootName The root of the name, or actual name if only one is being created. + * @param unique true to make the destinations unique to this pinger, false to share the + * numbering with all pingers on the same JVM. + * @param durable If the destinations are durable topics. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique, + boolean durable) throws JMSException + { + /*log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " + + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = " + + durable + "): called");*/ + + _pingDestinations = new ArrayList(); + + // Create the desired number of ping destinations and consumers for them. + // log.debug("Creating " + noOfDestinations + " destinations to ping."); + + for (int i = 0; i < noOfDestinations; i++) + { + Destination destination; + String id; + + // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag. + if (unique) + { + // log.debug("Creating unique destinations."); + id = "_" + _queueJVMSequenceID.incrementAndGet() + "_" + _connection.getClientID(); + } + else + { + // log.debug("Creating shared destinations."); + id = "_" + _queueSharedID.incrementAndGet(); + } + + // Check if this is a pub/sub pinger, in which case create topics. + if (_isPubSub) + { + destination = _producerSession.createTopic(rootName + id); + // log.debug("Created non-durable topic " + destination); + + if (durable) + { + _producerSession.createDurableSubscriber((Topic) destination, _connection.getClientID()); + } + } + // Otherwise this is a p2p pinger, in which case create queues. + else + { + destination = _producerSession.createQueue(rootName + id + _queueNamePostfix); + // log.debug("Created queue " + destination); + } + + // Keep the destination. + _pingDestinations.add(destination); + } + } + + /** + * Creates consumers for the specified destinations and registers this pinger to listen to their messages. + * + * @param destinations The destinations to listen to. + * @param selector A selector to filter the messages with. + * + * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through. + */ + public void createReplyConsumers(Collection destinations, String selector) throws JMSException + { + /*log.debug("public void createReplyConsumers(Collection destinations = " + destinations + + ", String selector = " + selector + "): called");*/ + + log.debug("There are " + destinations.size() + " destinations."); + log.debug("Creating " + _noOfConsumers + " consumers on each destination."); + log.debug("Total number of consumers is: " + (destinations.size() * _noOfConsumers)); + + for (Destination destination : destinations) + { + _consumer = new MessageConsumer[_noOfConsumers]; + + for (int i = 0; i < _noOfConsumers; i++) + { + // Create a consumer for the destination and set this pinger to listen to its messages. + _consumer[i] = _consumerSession[i].createConsumer(destination, selector, NO_LOCAL_DEFAULT); + + final int consumerNo = i; + + _consumer[i].setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + onMessageWithConsumerNo(message, consumerNo); + } + }); + + log.debug("Set consumer " + i + " to listen to replies sent to destination: " + destination); + } + } + } + + /** + * Stores the received message in the replies map, then resets the boolean latch that a thread waiting for a + * correlating reply may be waiting on. This is only done if the reply has a correlation id that is expected in the + * replies map. + * + * @param message The received message. + * @param consumerNo The consumer number within this test pinger instance. + */ + public void onMessageWithConsumerNo(Message message, int consumerNo) + { + // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo = " + consumerNo + "): called"); + try + { + long now = System.nanoTime(); + long timestamp = getTimestamp(message); + long pingTime = now - timestamp; + + // NDC.push("id" + instanceId + "/cons" + consumerNo); + + // Extract the messages correlation id. + String correlationID = message.getJMSCorrelationID(); + // log.debug("correlationID = " + correlationID); + + // int num = message.getIntProperty("MSG_NUM"); + // log.info("Message " + num + " received."); + + boolean isRedelivered = message.getJMSRedelivered(); + // log.debug("isRedelivered = " + isRedelivered); + + if (!isRedelivered) + { + // Countdown on the traffic light if there is one for the matching correlation id. + PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); + + if (perCorrelationId != null) + { + CountDownLatch trafficLight = perCorrelationId.trafficLight; + + // Restart the timeout timer on every message. + perCorrelationId.timeOutStart = System.nanoTime(); + + // log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); + + // Release waiting senders if there are some and using maxPending limit. + if ((_maxPendingSize > 0)) + { + // Decrement the count of sent but not yet received messages. + int unreceived = _unreceived.decrementAndGet(); + int unreceivedSize = + (unreceived * ((_messageSize == 0) ? 1 : _messageSize)) + / (_isPubSub ? getConsumersPerDestination() : 1); + + // log.debug("unreceived = " + unreceived); + // log.debug("unreceivedSize = " + unreceivedSize); + + // synchronized (_sendPauseMonitor) + // { + if (unreceivedSize < _maxPendingSize) + { + _sendPauseMonitor.poll(); + } + // } + } + + // Decrement the countdown latch. Before this point, it is possible that two threads might enter this + // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block + // ensures that each thread will get a unique value for the remaining messages. + long trueCount; + long remainingCount; + + synchronized (trafficLight) + { + trafficLight.countDown(); + + trueCount = trafficLight.getCount(); + remainingCount = trueCount - 1; + + // NDC.push("/rem" + remainingCount); + + // log.debug("remainingCount = " + remainingCount); + // log.debug("trueCount = " + trueCount); + + // Commit on transaction batch size boundaries. At this point in time the waiting producer + // remains blocked, even on the last message. + // Commit count is divided by noOfConsumers in p2p mode, so that each consumer only commits on + // each batch boundary. For pub/sub each consumer gets every message so no division is done. + // When running in client ack mode, an ack is done instead of a commit, on the commit batch + // size boundaries. + long commitCount = _isPubSub ? remainingCount : (remainingCount / _noOfConsumers); + // log.debug("commitCount = " + commitCount); + + if ((commitCount % _txBatchSize) == 0) + { + if (_consAckMode == 2) + { + // log.debug("Doing client ack for consumer " + consumerNo + "."); + message.acknowledge(); + } + else + { + // log.debug("Trying commit for consumer " + consumerNo + "."); + commitTx(_consumerSession[consumerNo]); + // log.info("Tx committed on consumer " + consumerNo); + } + } + + // Forward the message and remaining count to any interested chained message listener. + if (_chainedMessageListener != null) + { + _chainedMessageListener.onMessage(message, (int) remainingCount, pingTime); + } + + // Check if this is the last message, in which case release any waiting producers. This is done + // after the transaction has been committed and any listeners notified. + if (trueCount == 1) + { + trafficLight.countDown(); + } + } + } + else + { + log.warn("Got unexpected message with correlationId: " + correlationID); + } + } + else + { + log.warn("Got redelivered message, ignoring."); + } + } + catch (JMSException e) + { + log.warn("There was a JMSException: " + e.getMessage(), e); + } + finally + { + // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo): ending"); + // NDC.clear(); + } + } + + /** + * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out + * before a reply arrives, then a null reply is returned from this method. This method allows the caller to specify + * the correlation id. + * + * @param message The message to send. If this is null, one is generated. + * @param numPings The number of ping messages to send. + * @param timeout The timeout in milliseconds. + * @param messageCorrelationId The message correlation id. If this is null, one is generated. + * + * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait + * for all prematurely. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + * @throws InterruptedException When interrupted by a timeout + */ + public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) + throws JMSException, InterruptedException + { + /*log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ + + // Generate a unique correlation id to put on the messages before sending them, if one was not specified. + if (messageCorrelationId == null) + { + messageCorrelationId = Long.toString(_correlationIdGenerator.incrementAndGet()); + } + + try + { + // NDC.push("prod"); + + // Create a count down latch to count the number of replies with. This is created before the messages are + // sent so that the replies cannot be received before the count down is created. + // One is added to this, so that the last reply becomes a special case. The special case is that the + // chained message listener must be called before this sender can be unblocked, but that decrementing the + // countdown needs to be done before the chained listener can be called. + PerCorrelationId perCorrelationId = new PerCorrelationId(); + + perCorrelationId.trafficLight = new CountDownLatch(getExpectedNumPings(numPings) + 1); + perCorrelationIds.put(messageCorrelationId, perCorrelationId); + + // Set up the current time as the start time for pinging on the correlation id. This is used to determine + // timeouts. + perCorrelationId.timeOutStart = System.nanoTime(); + + // Send the specifed number of messages. + pingNoWaitForReply(message, numPings, messageCorrelationId); + + boolean timedOut; + boolean allMessagesReceived; + int numReplies; + + do + { + // Block the current thread until replies to all the messages are received, or it times out. + perCorrelationId.trafficLight.await(timeout, TimeUnit.MILLISECONDS); + + // Work out how many replies were receieved. + numReplies = getExpectedNumPings(numPings) - (int) perCorrelationId.trafficLight.getCount(); + + allMessagesReceived = numReplies == getExpectedNumPings(numPings); + + // log.debug("numReplies = " + numReplies); + // log.debug("allMessagesReceived = " + allMessagesReceived); + + // Recheck the timeout condition. + long now = System.nanoTime(); + long lastMessageReceievedAt = perCorrelationId.timeOutStart; + timedOut = (now - lastMessageReceievedAt) > (timeout * 1000000); + + // log.debug("now = " + now); + // log.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); + } + while (!timedOut && !allMessagesReceived); + + if ((numReplies < getExpectedNumPings(numPings)) && _verbose) + { + log.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); + } + else if (_verbose) + { + log.info("Got all replies on id, " + messageCorrelationId); + } + + // commitTx(_consumerSession); + + // log.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); + + return numReplies; + } + // Ensure that the message countdown latch is always removed from the reply map. The reply map is long lived, + // so will be a memory leak if this is not done. + finally + { + // NDC.pop(); + perCorrelationIds.remove(messageCorrelationId); + } + } + + /** + * Sends the specified number of ping messages and does not wait for correlating replies. + * + * @param message The message to send. + * @param numPings The number of pings to send. + * @param messageCorrelationId A correlation id to place on all messages sent. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + */ + public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException + { + /*log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings + + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ + + if (message == null) + { + message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent); + } + + message.setJMSCorrelationID(messageCorrelationId); + + // Set up a committed flag to detect uncommitted messages at the end of the send loop. This may occurr if the + // transaction batch size is not a factor of the number of pings. In which case an extra commit at the end is + // needed. + boolean committed = false; + + // Send all of the ping messages. + for (int i = 0; i < numPings; i++) + { + // Re-timestamp the message. + // message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); + + // Send the message, passing in the message count. + committed = sendMessage(i, message); + + // Spew out per message timings on every message sonly in verbose mode. + /*if (_verbose) + { + log.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); + }*/ + } + + // Call commit if the send loop finished before reaching a batch size boundary so there may still be uncommitted messages. + if (!committed) + { + commitTx(_producerSession); + } + } + + /** + * Sends the sepcified message, applies rate limiting and possibly commits the current transaction. The count of + * messages sent so far must be specified and is used to round robin the ping destinations (where there are more + * than one), and to determine if the transaction batch size has been reached and the sent messages should be + * committed. + * + * @param i The count of messages sent so far in a loop of multiple calls to this send method. + * @param message The message to send. + * + * @return true if the messages were committed, false otherwise. + * + * @throws JMSException All underlyiung JMSExceptions are allowed to fall through. + */ + protected boolean sendMessage(int i, Message message) throws JMSException + { + try + { + NDC.push("id" + instanceId + "/prod"); + + // log.debug("protected boolean sendMessage(int i = " + i + ", Message message): called"); + // log.debug("_txBatchSize = " + _txBatchSize); + + // Round robin the destinations as the messages are sent. + Destination destination = _pingDestinations.get(i % _pingDestinations.size()); + + // Prompt the user to kill the broker when doing failover testing. + _failBeforeSend = waitForUserToPromptOnFailure(_failBeforeSend); + + // Get the test setup for the correlation id. + String correlationID = message.getJMSCorrelationID(); + PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); + + // If necessary, wait until the max pending message size comes within its limit. + if (_maxPendingSize > 0) + { + synchronized (_sendPauseMonitor) + { + // Used to keep track of the number of times that send has to wait. + int numWaits = 0; + + // The maximum number of waits before the test gives up and fails. This has been chosen to correspond with + // the test timeout. + int waitLimit = (int) (TIMEOUT_DEFAULT / 10000); + + while (true) + { + // Get the size estimate of sent but not yet received messages. + int unreceived = _unreceived.get(); + int unreceivedSize = + (unreceived * ((_messageSize == 0) ? 1 : _messageSize)) + / (_isPubSub ? getConsumersPerDestination() : 1); + + // log.debug("unreceived = " + unreceived); + // log.debug("unreceivedSize = " + unreceivedSize); + // log.debug("_maxPendingSize = " + _maxPendingSize); + + if (unreceivedSize > _maxPendingSize) + { + // log.debug("unreceived size estimate over limit = " + unreceivedSize); + + // Fail the test if the send has had to wait more than the maximum allowed number of times. + if (numWaits > waitLimit) + { + String errorMessage = + "Send has had to wait for the unreceivedSize (" + unreceivedSize + + ") to come below the maxPendingSize (" + _maxPendingSize + ") more that " + waitLimit + + " times."; + log.warn(errorMessage); + throw new RuntimeException(errorMessage); + } + + // Wait on the send pause barrier for the limit to be re-established. + try + { + long start = System.nanoTime(); + // _sendPauseMonitor.wait(10000); + _sendPauseMonitor.offer(new Object(), 10000, TimeUnit.MILLISECONDS); + long end = System.nanoTime(); + + // Count the wait only if it was for > 99% of the requested wait time. + if (((float) (end - start) / (float) (10000 * 1000000L)) > 0.99) + { + numWaits++; + } + } + catch (InterruptedException e) + { + // Restore the interrupted status + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + } + else + { + break; + } + } + } + } + + // Send the message either to its round robin destination, or its default destination. + // int num = numSent.incrementAndGet(); + // message.setIntProperty("MSG_NUM", num); + setTimestamp(message); + + if (destination == null) + { + _producer.send(message); + } + else + { + _producer.send(destination, message); + } + + // Increase the unreceived size, this may actually happen after the message is received. + // The unreceived size is incremented by the number of consumers that will get a copy of the message, + // in pub/sub mode. + if (_maxPendingSize > 0) + { + int newUnreceivedCount = _unreceived.addAndGet(_isPubSub ? getConsumersPerDestination() : 1); + // log.debug("newUnreceivedCount = " + newUnreceivedCount); + } + + // Apply message rate throttling if a rate limit has been set up. + if (_rateLimiter != null) + { + _rateLimiter.throttle(); + } + + // Call commit every time the commit batch size is reached. + boolean committed = false; + + // Commit on every transaction batch size boundary. Here i + 1 is the count of actual messages sent. + if (((i + 1) % _txBatchSize) == 0) + { + // log.debug("Trying commit on producer session."); + committed = commitTx(_producerSession); + } + + return committed; + } + finally + { + NDC.clear(); + } + } + + /** + * If the specified fail flag is set, this method waits for the user to cause a failure and then indicate to the + * test that the failure has occurred, before the method returns. + * + * @param failFlag The fail flag to test. + * + * @return The new value for the fail flag. If the {@link #_failOnce} flag is set, then each fail flag is only + * used once, then reset. + */ + private boolean waitForUserToPromptOnFailure(boolean failFlag) + { + if (failFlag) + { + if (_failOnce) + { + failFlag = false; + } + + // log.debug("Failing Before Send"); + waitForUser(KILL_BROKER_PROMPT); + } + + return failFlag; + } + + /** + * Implements a single iteration of the ping loop. This sends the number of pings specified by the transaction batch + * size property, and waits for replies to all of them. Any errors cause the publish flag to be cleared, which will + * terminate the pinger. + */ + public void pingLoop() + { + try + { + // Generate a sample message and time stamp it. + Message msg = getTestMessage(_replyDestination, _messageSize, _persistent); + // setTimestamp(msg); + + // Send the message and wait for a reply. + pingAndWaitForReply(msg, TX_BATCH_SIZE_DEFAULT, TIMEOUT_DEFAULT, null); + } + catch (JMSException e) + { + _publish = false; + // log.debug("There was a JMSException: " + e.getMessage(), e); + } + catch (InterruptedException e) + { + _publish = false; + // log.debug("There was an interruption: " + e.getMessage(), e); + } + } + + /** + * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set + * here. + * + * @param messageListener The chained message listener. + */ + public void setChainedMessageListener(ChainedMessageListener messageListener) + { + _chainedMessageListener = messageListener; + } + + /** Removes any chained message listeners from this pinger. */ + public void removeChainedMessageListener() + { + _chainedMessageListener = null; + } + + /** + * Generates a test message of the specified size, with the specified reply-to destination and persistence flag. + * + * @param replyQueue The reply-to destination for the message. + * @param messageSize The desired size of the message in bytes. + * @param persistent true if the message should use persistent delivery, false otherwise. + * + * @return A freshly generated test message. + * + * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. + */ + public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException + { + // return TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); + return TestUtils.createTestMessageOfSize(_producerSession, messageSize); + } + + /** + * Sets the current time in nanoseconds as the timestamp on the message. + * + * @param msg The message to timestamp. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + protected void setTimestamp(Message msg) throws JMSException + { + /*if (((AMQSession)_producerSession).isStrictAMQP()) + { + ((AMQMessage)msg).setTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME), System.nanoTime()); + } + else + {*/ + msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); + // } + } + + /** + * Extracts the nanosecond timestamp from a message. + * + * @param msg The message to extract the time stamp from. + * + * @return The timestamp in nanos. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + protected long getTimestamp(Message msg) throws JMSException + { + /*if (((AMQSession)_producerSession).isStrictAMQP()) + { + Long value = ((AMQMessage)msg).getTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME)); + + return (value == null) ? 0L : value; + } + else + {*/ + return msg.getLongProperty(PingPongProducer.MESSAGE_TIMESTAMP_PROPNAME); + // } + } + + /** + * Stops the ping loop by clearing the publish flag. The current loop will complete when it notices that this flag + * has been cleared. + */ + public void stop() + { + _publish = false; + } + + /** + * Starts the producer and consumer connections. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + public void start() throws JMSException + { + // log.debug("public void start(): called"); + + _connection.start(); + // log.debug("Producer started."); + + for (int i = 0; i < _noOfConsumers; i++) + { + _consumerConnection[i].start(); + // log.debug("Consumer " + i + " started."); + } + } + + /** Implements a ping loop that repeatedly pings until the publish flag becomes false. */ + public void run() + { + // Keep running until the publish flag is cleared. + while (_publish) + { + pingLoop(); + } + } + + /** + * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the + * connection, this clears the publish flag which in turn will halt the ping loop. + * + * @param e The exception that triggered this callback method. + */ + public void onException(JMSException e) + { + // log.debug("public void onException(JMSException e = " + e + "): called", e); + _publish = false; + } + + /** + * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered + * with the runtime system as a shutdown hook. + * + * @return A shutdown hook for the ping loop. + */ + public Thread getShutdownHook() + { + return new Thread(new Runnable() + { + public void run() + { + stop(); + } + }); + } + + /** + * Closes all of the producer and consumer connections. + * + * @throws JMSException All JMSException are allowed to fall through. + */ + public void close() throws JMSException + { + // log.debug("public void close(): called"); + + try + { + if (_connection != null) + { + // log.debug("Before close producer connection."); + _connection.close(); + // log.debug("Closed producer connection."); + } + + for (int i = 0; i < _noOfConsumers; i++) + { + if (_consumerConnection[i] != null) + { + // log.debug("Before close consumer connection " + i + "."); + _consumerConnection[i].close(); + // log.debug("Closed consumer connection " + i + "."); + } + } + } + finally + { + _connection = null; + _producerSession = null; + _consumerSession = null; + _consumerConnection = null; + _producer = null; + _consumer = null; + _pingDestinations = null; + _replyDestination = null; + } + } + + /** + * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not a + * transactional controlSession, this method does nothing (unless the failover after send flag is set). + * + *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit is + * applied. This flag applies whether the pinger is transactional or not. + * + *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the commit + * is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker after the + * commit is applied. These flags will only apply if using a transactional pinger. + * + * @param session The controlSession to commit + * + * @return true if the controlSession was committed, false if it was not. + * + * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + * + * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit + * method, because commits only apply to transactional pingers, but fail after send applied to transactional and + * non-transactional alike. + */ + protected boolean commitTx(Session session) throws JMSException + { + // log.debug("protected void commitTx(Session session): called"); + + boolean committed = false; + + _failAfterSend = waitForUserToPromptOnFailure(_failAfterSend); + + if (session.getTransacted()) + { + // log.debug("Session is transacted."); + + try + { + _failBeforeCommit = waitForUserToPromptOnFailure(_failBeforeCommit); + + long start = System.nanoTime(); + session.commit(); + committed = true; + // log.debug("Time taken to commit :" + ((System.nanoTime() - start) / 1000000f) + " ms"); + + _failAfterCommit = waitForUserToPromptOnFailure(_failAfterCommit); + + // log.debug("Session Commited."); + } + catch (JMSException e) + { + // log.debug("JMSException on commit:" + e.getMessage(), e); + + try + { + session.rollback(); + // log.debug("Message rolled back."); + } + catch (JMSException jmse) + { + // log.debug("JMSE on rollback:" + jmse.getMessage(), jmse); + + // Both commit and rollback failed. Throw the rollback exception. + throw jmse; + } + } + } + + return committed; + } + + /** + * Outputs a prompt to the console and waits for the user to press return. + * + * @param prompt The prompt to display on the console. + */ + public void waitForUser(String prompt) + { + System.out.println(prompt); + + try + { + System.in.read(); + } + catch (IOException e) + { + // Ignored. + } + + System.out.println("Continuing."); + } + + /** + * Gets the number of consumers that are listening to each destination in the test. + * + * @return int The number of consumers subscribing to each topic. + */ + public int getConsumersPerDestination() + { + return _noOfConsumers; + } + + /** + * Calculates how many pings are expected to be received for the given number sent. + * + * @param numpings The number of pings that will be sent. + * + * @return The number that should be received, for the test to pass. + */ + public int getExpectedNumPings(int numpings) + { + // log.debug("public int getExpectedNumPings(int numpings = " + numpings + "): called"); + + // log.debug("Each ping will be received by " + (_isPubSub ? getConsumersPerDestination() : 1) + " consumers."); + + return numpings * (_isPubSub ? getConsumersPerDestination() : 1); + } + + /** + * Defines a chained message listener interface that can be attached to this pinger. Whenever this pinger's {@link + * PingPongProducer#onMessageWithConsumerNo} method is called, the chained listener set through the {@link + * PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected count of + * messages with that correlation id. + * + *

    Provided only one pinger is producing messages with that correlation id, the chained listener will always be + * given unique message counts. It will always be called while the producer waiting for all messages to arrive is + * still blocked. + */ + public static interface ChainedMessageListener + { + /** + * Notifies interested listeners about message arrival and important test stats, the number of messages + * remaining in the test, and the messages send timestamp. + * + * @param message The newly arrived message. + * @param remainingCount The number of messages left to complete the test. + * @param latency The nanosecond latency of the message. + * + * @throws JMSException Any JMS exceptions is allowed to fall through. + */ + public void onMessage(Message message, int remainingCount, long latency) throws JMSException; + } + + /** + * Holds information on each correlation id. The countdown latch, the current timeout timer... More stuff to be + * added to this: read/write lock to make onMessage more concurrent as described in class header comment. + */ + protected static class PerCorrelationId + { + /** Holds a countdown on number of expected messages. */ + CountDownLatch trafficLight; + + /** Holds the last timestamp that the timeout was reset to. */ + Long timeOutStart; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java new file mode 100644 index 0000000000..2610b32220 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java @@ -0,0 +1,251 @@ +/* + * + * 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.qpid.requestreply; + +import junit.framework.Assert; +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +import org.apache.qpid.junit.extensions.AsymptoticTestCase; +import org.apache.qpid.junit.extensions.util.ParsedProperties; +import org.apache.qpid.junit.extensions.util.TestContextProperties; + +import javax.jms.*; + +/** + * PingPongTestPerf is a full round trip ping test, that has been written with the intention of being scaled up to run + * many times simultaneously to simluate many clients/producer/connections. A full round trip ping sends a message from + * a producer to a conumer, then the consumer replies to the message on a temporary queue. + * + *

    A single run of the test using the default JUnit test runner will result in the sending and timing of the number + * of pings specified by the test size and time how long it takes for all of these to complete. This test may be scaled + * up using a suitable JUnit test runner. See {@link org.apache.qpid.junit.extensions.TKTestRunner} for more + * information on how to do this. + * + *

    The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a + * temporary queue for replies. This setup is only established once for all the test repeats, but each test threads + * gets its own connection/producer/consumer, this is only re-established if the connection is lost. + * + *

    The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that + * is the name of the temporary queue, fires off many messages on the original queue and waits for them all to come + * back on the temporary queue. + * + *

    Configurable test properties: message size, transacted or not, persistent or not. Broker connection details. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    + */ +public class PingPongTestPerf extends AsymptoticTestCase +{ + private static Logger _logger = Logger.getLogger(PingPongTestPerf.class); + + /** Thread local to hold the per-thread test setup fields. */ + ThreadLocal threadSetup = new ThreadLocal(); + + // Set up a property reader to extract the test parameters from. Once ContextualProperties is available in + // the project dependencies, use it to get property overrides for configurable tests and to notify the test runner + // of the test parameters to log with the results. It also providers some basic type parsing convenience methods. + // private Properties testParameters = System.getProperties(); + private ParsedProperties testParameters = + TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/); + + public PingPongTestPerf(String name) + { + super(name); + + _logger.debug(testParameters); + + // Sets up the test parameters with defaults. + /*testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME, + Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.MESSAGE_SIZE_PROPNAME, + Integer.toString(PingPongProducer.MESSAGE_SIZE_DEAFULT)); + testParameters.setPropertyIfNull(PingPongProducer.PING_QUEUE_NAME_PROPNAME, + PingPongProducer.PING_QUEUE_NAME_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.PERSISTENT_MODE_PROPNAME, + Boolean.toString(PingPongProducer.PERSISTENT_MODE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.TRANSACTED_PROPNAME, + Boolean.toString(PingPongProducer.TRANSACTED_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.BROKER_PROPNAME, PingPongProducer.BROKER_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.USERNAME_PROPNAME, PingPongProducer.USERNAME_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.PASSWORD_PROPNAME, PingPongProducer.PASSWORD_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.VIRTUAL_HOST_PROPNAME, PingPongProducer.VIRTUAL_HOST_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.VERBOSE_PROPNAME, + Boolean.toString(PingPongProducer.VERBOSE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.RATE_PROPNAME, Integer.toString(PingPongProducer.RATE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.PUBSUB_PROPNAME, + Boolean.toString(PingPongProducer.PUBSUB_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME, + Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.TIMEOUT_PROPNAME, Long.toString(PingPongProducer.TIMEOUT_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.DESTINATION_COUNT_PROPNAME, + Integer.toString(PingPongProducer.DESTINATION_COUNT_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_COMMIT_PROPNAME, + PingPongProducer.FAIL_AFTER_COMMIT_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_COMMIT_PROPNAME, + PingPongProducer.FAIL_BEFORE_COMMIT_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_SEND_PROPNAME, + PingPongProducer.FAIL_AFTER_SEND_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_SEND_PROPNAME, + PingPongProducer.FAIL_BEFORE_SEND_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_ONCE_PROPNAME, PingPongProducer.FAIL_ONCE_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.UNIQUE_DESTS_PROPNAME, + Boolean.toString(PingPongProducer.UNIQUE_DESTS_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.ACK_MODE_PROPNAME, + Integer.toString(PingPongProducer.ACK_MODE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.PAUSE_AFTER_BATCH_PROPNAME, + PingPongProducer.PAUSE_AFTER_BATCH_DEFAULT);*/ + } + + /** + * Compile all the tests into a test suite. + */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Ping-Pong Performance Tests"); + + // Run performance tests in read committed mode. + suite.addTest(new PingPongTestPerf("testPingPongOk")); + + return suite; + } + + private static void setSystemPropertyIfNull(String propName, String propValue) + { + if (System.getProperty(propName) == null) + { + System.setProperty(propName, propValue); + } + } + + public void testPingPongOk(int numPings) throws Exception + { + // Get the per thread test setup to run the test through. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Generate a sample message. This message is already time stamped and has its reply-to destination set. + Message msg = + perThreadSetup._testPingProducer.getTestMessage(perThreadSetup._testPingProducer.getReplyDestinations().get(0), + testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), + testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); + + // Send the message and wait for a reply. + int numReplies = + perThreadSetup._testPingProducer.pingAndWaitForReply(msg, numPings, PingPongProducer.TIMEOUT_DEFAULT, null); + + // Fail the test if the timeout was exceeded. + if (numReplies != numPings) + { + Assert.fail("The ping timed out, got " + numReplies + " out of " + numPings); + } + } + + /** + * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. + */ + public void threadSetUp() + { + try + { + PerThreadSetup perThreadSetup = new PerThreadSetup(); + + // Extract the test set up paramaeters. + String brokerDetails = testParameters.getProperty(PingPongProducer.BROKER_PROPNAME); + String username = testParameters.getProperty(PingPongProducer.USERNAME_PROPNAME); + String password = testParameters.getProperty(PingPongProducer.PASSWORD_PROPNAME); + String virtualPath = testParameters.getProperty(PingPongProducer.VIRTUAL_HOST_PROPNAME); + String destinationName = testParameters.getProperty(PingPongProducer.PING_QUEUE_NAME_PROPNAME); + boolean persistent = testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME); + boolean transacted = testParameters.getPropertyAsBoolean(PingPongProducer.TRANSACTED_PROPNAME); + String selector = testParameters.getProperty(PingPongProducer.SELECTOR_PROPNAME); + boolean verbose = testParameters.getPropertyAsBoolean(PingPongProducer.VERBOSE_PROPNAME); + boolean pubsub = testParameters.getPropertyAsBoolean(PingPongProducer.PUBSUB_PROPNAME); + + synchronized (this) + { + // Establish a bounce back client on the ping queue to bounce back the pings. + perThreadSetup._testPingBouncer = + new PingPongBouncer(brokerDetails, username, password, virtualPath, destinationName, persistent, + transacted, selector, verbose, pubsub); + + // Start the connections for client and producer running. + perThreadSetup._testPingBouncer.getConnection().start(); + + // Establish a ping-pong client on the ping queue to send the pings and receive replies with. + perThreadSetup._testPingProducer = new PingPongProducer(testParameters); + perThreadSetup._testPingProducer.establishConnection(true, true); + perThreadSetup._testPingProducer.start(); + } + + // Attach the per-thread set to the thread. + threadSetup.set(perThreadSetup); + } + catch (Exception e) + { + _logger.warn("There was an exception during per thread setup.", e); + } + } + + /** + * Performs test fixture clean + */ + public void threadTearDown() + { + _logger.debug("public void threadTearDown(): called"); + + try + { + // Get the per thread test fixture. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Close the pingers so that it cleans up its connection cleanly. + synchronized (this) + { + perThreadSetup._testPingProducer.close(); + // perThreadSetup._testPingBouncer.close(); + } + + // Ensure the per thread fixture is reclaimed. + threadSetup.remove(); + } + catch (JMSException e) + { + _logger.warn("There was an exception during per thread tear down."); + } + } + + protected static class PerThreadSetup + { + /** + * Holds the test ping-pong producer. + */ + private PingPongProducer _testPingProducer; + + /** + * Holds the test ping client. + */ + private PingPongBouncer _testPingBouncer; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java new file mode 100644 index 0000000000..f699295b06 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java @@ -0,0 +1,199 @@ +/* + * + * 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.qpid.test.testcases; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; + +import org.apache.qpid.test.framework.Assertion; +import org.apache.qpid.test.framework.Circuit; +import org.apache.qpid.test.framework.FrameworkBaseCase; +import org.apache.qpid.test.framework.MessagingTestConfigProperties; +import org.apache.qpid.test.framework.sequencers.CircuitFactory; + +import org.apache.qpid.junit.extensions.TestThreadAware; +import org.apache.qpid.junit.extensions.TimingController; +import org.apache.qpid.junit.extensions.TimingControllerAware; +import org.apache.qpid.junit.extensions.util.ParsedProperties; +import org.apache.qpid.junit.extensions.util.TestContextProperties; + +import java.util.LinkedList; + +/** + * MessageThroughputPerf runs a test over a {@link Circuit} controlled by the test parameters. It logs timings of + * the time required to receive samples consisting of batches of messages. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Measure message throughput accross a test circuit. {@link Circuit} + *
    + * + * @todo Check that all of the messages were sent. Check that the receiving end got the same number of messages as + * the publishing end. + * + * @todo Set this up to run with zero sized tests. Size zero means send forever. Continuous sending to be interrupted + * by completion of the test duration, or shutdown hook when the user presses Ctrl-C. + */ +public class MessageThroughputPerf extends FrameworkBaseCase implements TimingControllerAware, TestThreadAware +{ + /** Used for debugging. */ + private static final Logger log = Logger.getLogger(MessageThroughputPerf.class); + + /** Holds the timing controller, used to log test timings from self-timed tests. */ + private TimingController timingController; + + /** Thread local to hold the per-thread test setup fields. */ + ThreadLocal threadSetup = new ThreadLocal(); + + /** + * Creates a new test case with the specified name. + * + * @param name The test case name. + */ + public MessageThroughputPerf(String name) + { + super(name); + } + + /** + * Performs the a basic P2P test case. + * + * @param numMessages The number of messages to send in the test. + */ + public void testThroughput(int numMessages) + { + log.debug("public void testThroughput(): called"); + + PerThreadSetup setup = threadSetup.get(); + assertNoFailures(setup.testCircuit.test(numMessages, new LinkedList())); + } + + /** + * Should provide a translation from the junit method name of a test to its test case name as known to the test + * clients that will run the test. The purpose of this is to convert the JUnit method name into the correct test + * case name to place into the test invite. For example the method "testP2P" might map onto the interop test case + * name "TC2_BasicP2P". + * + * @param methodName The name of the JUnit test method. + * + * @return The name of the corresponding interop test case. + */ + public String getTestCaseNameForTestMethod(String methodName) + { + log.debug("public String getTestCaseNameForTestMethod(String methodName = " + methodName + "): called"); + + return "DEFAULT_CIRCUIT_TEST"; + } + + /** + * Used by test runners that can supply a {@link org.apache.qpid.junit.extensions.TimingController} to set the + * controller on an aware test. + * + * @param controller The timing controller. + */ + public void setTimingController(TimingController controller) + { + timingController = controller; + } + + /** + * Overrides the parent setUp method so that the in-vm broker creation is not done on a per test basis. + * + * @throws Exception Any exceptions allowed to fall through and fail the test. + */ + protected void setUp() throws Exception + { + NDC.push(getName()); + + testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults); + } + + /** + * Overrides the parent setUp method so that the in-vm broker clean-up is not done on a per test basis. + */ + protected void tearDown() + { + NDC.pop(); + } + + /** + * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. + */ + public void threadSetUp() + { + // Run the test setup tasks. This may create an in-vm broker, if a decorator has injected a task for this. + taskHandler.runSetupTasks(); + + // Get the test parameters, any overrides on the command line will have been applied. + ParsedProperties testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults); + + // Customize the test parameters. + testProps.setProperty("TEST_NAME", "DEFAULT_CIRCUIT_TEST"); + testProps.setProperty(MessagingTestConfigProperties.SEND_DESTINATION_NAME_ROOT_PROPNAME, "testqueue"); + + // Get the test circuit factory to create test circuits and run the standard test procedure through. + CircuitFactory circuitFactory = getCircuitFactory(); + + // Create the test circuit. This projects the circuit onto the available test nodes and connects it up. + Circuit testCircuit = circuitFactory.createCircuit(testProps); + + // Store the test configuration for the thread. + PerThreadSetup setup = new PerThreadSetup(); + setup.testCircuit = testCircuit; + threadSetup.set(setup); + } + + /** + * Called when a test thread is destroyed. + */ + public void threadTearDown() + { + // Run the test teardown tasks. This may destroy the in-vm broker, if a decorator has injected a task for this. + taskHandler.runSetupTasks(); + } + + /** + * Holds the per-thread test configurations. + */ + protected static class PerThreadSetup + { + /** Holds the test circuit to run tests on. */ + Circuit testCircuit; + } + + /** + * Compiles all the tests in this class into a suite. + * + * @return The test suite. + */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Qpid Throughput Performance Tests"); + + suite.addTest(new MessageThroughputPerf("testThroughput")); + + return suite; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java new file mode 100644 index 0000000000..d5c0979399 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java @@ -0,0 +1,326 @@ +/* + * + * 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.qpid.topic; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.config.ConnectorConfig; +import org.apache.qpid.config.Connector; +import org.apache.qpid.config.AbstractConfig; + +import javax.jms.Connection; + +public class Config extends AbstractConfig implements ConnectorConfig +{ + + private String host = "localhost"; + private int port = 5672; + private String factory = null; + + private int payload = 256; + private int messages = 1000; + private int clients = 1; + private int batch = 1; + private long delay = 1; + private int warmup; + private int ackMode= AMQSession.NO_ACKNOWLEDGE; + private String clientId; + private String subscriptionId; + private String selector; + private String destinationName; + private boolean persistent; + private boolean transacted; + private int destinationsCount; + private int batchSize; + private int rate; + private boolean ispubsub; + private long timeout; + + public Config() + { + } + + public int getAckMode() + { + return ackMode; + } + + public void setPayload(int payload) + { + this.payload = payload; + } + + public int getPayload() + { + return payload; + } + + void setClients(int clients) + { + this.clients = clients; + } + + int getClients() + { + return clients; + } + + void setMessages(int messages) + { + this.messages = messages; + } + + public int getMessages() + { + return messages; + } + + public int getBatchSize() + { + return batchSize; + } + + public int getRate() + { + return rate; + } + + public int getDestinationsCount() + { + return destinationsCount; + } + + public String getHost() + { + return host; + } + + public void setHost(String host) + { + this.host = host; + } + + public int getPort() + { + return port; + } + + public String getFactory() + { + return factory; + } + + public void setPort(int port) + { + this.port = port; + } + + int getBatch() + { + return batch; + } + + void setBatch(int batch) + { + this.batch = batch; + } + + int getWarmup() + { + return warmup; + } + + void setWarmup(int warmup) + { + this.warmup = warmup; + } + + public long getDelay() + { + return delay; + } + + public void setDelay(long delay) + { + this.delay = delay; + } + + public long getTimeout() + { + return timeout; + } + + public void setTimeout(long time) + { + this.timeout = time; + } + + public String getClientId() + { + return clientId; + } + + public String getSubscriptionId() + { + return subscriptionId; + } + + public String getSelector() + { + return selector; + } + + public String getDestination() + { + return destinationName; + } + + public boolean usePersistentMessages() + { + return persistent; + } + + public boolean isTransacted() + { + return transacted; + } + + public boolean isPubSub() + { + return ispubsub; + } + + public void setOption(String key, String value) + { + if("-host".equalsIgnoreCase(key)) + { + setHost(value); + } + else if("-port".equalsIgnoreCase(key)) + { + try + { + setPort(Integer.parseInt(value)); + } + catch(NumberFormatException e) + { + throw new RuntimeException("Bad port number: " + value, e); + } + } + else if("-payload".equalsIgnoreCase(key)) + { + setPayload(parseInt("Bad payload size", value)); + } + else if("-messages".equalsIgnoreCase(key)) + { + setMessages(parseInt("Bad message count", value)); + } + else if("-clients".equalsIgnoreCase(key)) + { + setClients(parseInt("Bad client count", value)); + } + else if("-batch".equalsIgnoreCase(key)) + { + setBatch(parseInt("Bad batch count", value)); + } + else if("-delay".equalsIgnoreCase(key)) + { + setDelay(parseLong("Bad batch delay", value)); + } + else if("-warmup".equalsIgnoreCase(key)) + { + setWarmup(parseInt("Bad warmup count", value)); + } + else if("-ack".equalsIgnoreCase(key)) + { + ackMode = parseInt("Bad ack mode", value); + } + else if("-factory".equalsIgnoreCase(key)) + { + factory = value; + } + else if("-clientId".equalsIgnoreCase(key)) + { + clientId = value; + } + else if("-subscriptionId".equalsIgnoreCase(key)) + { + subscriptionId = value; + } + else if("-persistent".equalsIgnoreCase(key)) + { + persistent = "true".equalsIgnoreCase(value); + } + else if("-transacted".equalsIgnoreCase(key)) + { + transacted = "true".equalsIgnoreCase(value); + } + else if ("-destinationscount".equalsIgnoreCase(key)) + { + destinationsCount = parseInt("Bad destinations count", value); + } + else if ("-batchsize".equalsIgnoreCase(key)) + { + batchSize = parseInt("Bad batch size", value); + } + else if ("-rate".equalsIgnoreCase(key)) + { + rate = parseInt("MEssage rate", value); + } + else if("-pubsub".equalsIgnoreCase(key)) + { + ispubsub = "true".equalsIgnoreCase(value); + } + else if("-selector".equalsIgnoreCase(key)) + { + selector = value; + } + else if("-destinationname".equalsIgnoreCase(key)) + { + destinationName = value; + } + else if("-timeout".equalsIgnoreCase(key)) + { + setTimeout(parseLong("Bad timeout data", value)); + } + else + { + System.out.println("Ignoring unrecognised option: " + key); + } + } + + static String getAckModeDescription(int ackMode) + { + switch(ackMode) + { + case AMQSession.NO_ACKNOWLEDGE: return "NO_ACKNOWLEDGE"; + case AMQSession.AUTO_ACKNOWLEDGE: return "AUTO_ACKNOWLEDGE"; + case AMQSession.CLIENT_ACKNOWLEDGE: return "CLIENT_ACKNOWLEDGE"; + case AMQSession.DUPS_OK_ACKNOWLEDGE: return "DUPS_OK_ACKNOWELDGE"; + case AMQSession.PRE_ACKNOWLEDGE: return "PRE_ACKNOWLEDGE"; + } + return "AckMode=" + ackMode; + } + + public Connection createConnection() throws Exception + { + return new Connector().createConnection(this); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java new file mode 100644 index 0000000000..6dcea42bfe --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Listener.java @@ -0,0 +1,303 @@ +/* + * + * 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.qpid.topic; + +import java.util.Random; + +import javax.jms.*; + +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.exchange.ExchangeDefaults; + +/** + * This class has not kept up to date with the topic_listener in the cpp tests. It should provide identical behaviour for + * cross testing the java and cpp clients. + * + *

    How the cpp topic_publisher operates: + * It publishes text messages to the default topic exchange, on virtual host "/test", on the topic "topic_control", for + * the specified number of test messages to be sent. + * It publishes a report request message (on same topic), with the header text field "TYPE", value "REPORT_REQUEST", + * optionally within a transaction, and waits for the specified number of consumers to reply to this request. The + * listeners should reply to this message on a queue named "response", on virtual host "/test", with some sort of message + * about the number of messages received and how long it took, although the publisher never looks at the message content. + * The publisher then send a message (on the same topic), with the header text field "TYPE", value "TERMINATION_REQUEST", + * which the listener should close its connection and terminate upon receipt of. + * + * @todo I've added lots of field table types in the report message, just to check if the other end can decode them + * correctly. Not really the right place to test this, so remove them from + * {@link #createReportResponseMessage(String)} once a better test exists. + */ +public class Listener implements MessageListener +{ + private static Logger log = Logger.getLogger(Listener.class); + + public static final String CONTROL_TOPIC = "topic_control"; + public static final String RESPONSE_QUEUE = "response"; + + private final Topic _topic; + //private final Topic _control; + + private final Queue _response; + + /** Holds the connection to listen on. */ + private final Connection _connection; + + /** Holds the producer to send control messages on. */ + private final MessageProducer _controller; + + /** Holds the JMS session. */ + private final javax.jms.Session _session; + + /** Holds a flag to indicate that a timer has begun on the first message. Reset when report is sent. */ + private boolean init; + + /** Holds the count of messages received by this listener. */ + private int count; + + /** Used to hold the start time of the first message. */ + private long start; + private static String clientId; + + Listener(Connection connection, int ackMode, String name) throws Exception + { + log.debug("Listener(Connection connection = " + connection + ", int ackMode = " + ackMode + ", String name = " + name + + "): called"); + + _connection = connection; + _session = connection.createSession(false, ackMode); + + if (_session instanceof AMQSession) + { + _topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, CONTROL_TOPIC); + //_control = new AMQTopic(CONTROL_TOPIC); + _response = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, RESPONSE_QUEUE); + } + else + { + _topic = _session.createTopic(CONTROL_TOPIC); + //_control = _session.createTopic(CONTROL_TOPIC); + _response = _session.createQueue(RESPONSE_QUEUE); + } + + //register for events + if (name == null) + { + log.debug("Calling _factory.createTopicConsumer().setMessageListener(this)"); + createTopicConsumer().setMessageListener(this); + } + else + { + log.debug("Calling createDurableTopicConsumer(name).setMessageListener(this)"); + createDurableTopicConsumer(name).setMessageListener(this); + } + + _connection.start(); + + _controller = createControlPublisher(); + System.out.println("Waiting for messages " + Config.getAckModeDescription(ackMode) + + + ((name == null) + ? "" : (" (subscribed with name " + name + " and client id " + connection.getClientID() + ")")) + + "..."); + } + + public static void main(String[] argv) throws Exception + { + clientId = "Listener-" + System.currentTimeMillis(); + + NDC.push(clientId); + + Config config = new Config(); + config.setOptions(argv); + + //Connection con = config.createConnection(); + Connection con = + new AMQConnection("amqp://guest:guest@testid/test?brokerlist='" + config.getHost() + ":" + config.getPort() + + "'"); + + if (config.getClientId() != null) + { + con.setClientID(config.getClientId()); + } + + new Listener(con, config.getAckMode(), config.getSubscriptionId()); + + NDC.pop(); + NDC.remove(); + } + + /** + * Checks whether or not a text field on a message has the specified value. + * + * @param m The message to check. + * @param fieldName The name of the field to check. + * @param value The expected value of the field to compare with. + * + * @return trueIf the specified field has the specified value, fals otherwise. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + private static boolean checkTextField(Message m, String fieldName, String value) throws JMSException + { + log.debug("private static boolean checkTextField(Message m = " + m + ", String fieldName = " + fieldName + + ", String value = " + value + "): called"); + + String comp = m.getStringProperty(fieldName); + log.debug("comp = " + comp); + + boolean result = (comp != null) && comp.equals(value); + log.debug("result = " + result); + + return result; + } + + public void onMessage(Message message) + { + NDC.push(clientId); + + log.debug("public void onMessage(Message message = " + message + "): called"); + + if (!init) + { + start = System.nanoTime() / 1000000; + count = 0; + init = true; + } + + try + { + if (isShutdown(message)) + { + log.debug("Got a shutdown message."); + shutdown(); + } + else if (isReport(message)) + { + log.debug("Got a report request message."); + + // Send the report. + report(); + init = false; + } + } + catch (JMSException e) + { + log.warn("There was a JMSException during onMessage.", e); + } + finally + { + NDC.pop(); + } + } + + Message createReportResponseMessage(String msg) throws JMSException + { + Message message = _session.createTextMessage(msg); + + // Shove some more field table type in the message just to see if the other end can handle it. + message.setBooleanProperty("BOOLEAN", true); + message.setByteProperty("BYTE", (byte) 5); + message.setDoubleProperty("DOUBLE", Math.PI); + message.setFloatProperty("FLOAT", 1.0f); + message.setIntProperty("INT", 1); + message.setShortProperty("SHORT", (short) 1); + message.setLongProperty("LONG", (long) 1827361278); + message.setStringProperty("STRING", "hello"); + + return message; + } + + boolean isShutdown(Message m) throws JMSException + { + boolean result = checkTextField(m, "TYPE", "TERMINATION_REQUEST"); + + //log.debug("isShutdown = " + result); + + return result; + } + + boolean isReport(Message m) throws JMSException + { + boolean result = checkTextField(m, "TYPE", "REPORT_REQUEST"); + + //log.debug("isReport = " + result); + + return result; + } + + MessageConsumer createTopicConsumer() throws Exception + { + return _session.createConsumer(_topic); + } + + MessageConsumer createDurableTopicConsumer(String name) throws Exception + { + return _session.createDurableSubscriber(_topic, name); + } + + MessageProducer createControlPublisher() throws Exception + { + return _session.createProducer(_response); + } + + private void shutdown() + { + try + { + _session.close(); + _connection.stop(); + _connection.close(); + } + catch (Exception e) + { + e.printStackTrace(System.out); + } + } + + private void report() + { + log.debug("private void report(): called"); + + try + { + String msg = getReport(); + _controller.send(createReportResponseMessage(msg)); + log.debug("Sent report: " + msg); + } + catch (Exception e) + { + e.printStackTrace(System.out); + } + } + + private String getReport() + { + long time = ((System.nanoTime() / 1000000) - start); + + return "Received " + count + " in " + time + "ms"; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java new file mode 100644 index 0000000000..4efdc1cb56 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/MessageFactory.java @@ -0,0 +1,157 @@ +/* + * + * 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.qpid.topic; + +import javax.jms.*; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.exchange.ExchangeDefaults; + +/** + */ +class MessageFactory +{ + private static final char[] DATA = "abcdefghijklmnopqrstuvwxyz".toCharArray(); + + private final Session _session; + private final Topic _topic; + private final Topic _control; + private final byte[] _payload; + + MessageFactory(Session session) throws JMSException + { + this(session, 256); + } + + MessageFactory(Session session, int size) throws JMSException + { + _session = session; + if (session instanceof AMQSession) + { + _topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, "topic_control"); + _control = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, "topictest.control"); + } + else + { + _topic = session.createTopic("topic_control"); + _control = session.createTopic("topictest.control"); + } + + _payload = new byte[size]; + + for (int i = 0; i < size; i++) + { + _payload[i] = (byte) DATA[i % DATA.length]; + } + } + + private static boolean checkText(Message m, String s) + { + try + { + return (m instanceof TextMessage) && ((TextMessage) m).getText().equals(s); + } + catch (JMSException e) + { + e.printStackTrace(System.out); + + return false; + } + } + + Topic getTopic() + { + return _topic; + } + + Message createEventMessage() throws JMSException + { + BytesMessage msg = _session.createBytesMessage(); + msg.writeBytes(_payload); + + return msg; + } + + Message createShutdownMessage() throws JMSException + { + return _session.createTextMessage("SHUTDOWN"); + } + + Message createReportRequestMessage() throws JMSException + { + return _session.createTextMessage("REPORT"); + } + + Message createReportResponseMessage(String msg) throws JMSException + { + return _session.createTextMessage(msg); + } + + boolean isShutdown(Message m) + { + return checkText(m, "SHUTDOWN"); + } + + boolean isReport(Message m) + { + return checkText(m, "REPORT"); + } + + Object getReport(Message m) + { + try + { + return ((TextMessage) m).getText(); + } + catch (JMSException e) + { + e.printStackTrace(System.out); + + return e.toString(); + } + } + + MessageConsumer createTopicConsumer() throws Exception + { + return _session.createConsumer(_topic); + } + + MessageConsumer createDurableTopicConsumer(String name) throws Exception + { + return _session.createDurableSubscriber(_topic, name); + } + + MessageConsumer createControlConsumer() throws Exception + { + return _session.createConsumer(_control); + } + + MessageProducer createTopicPublisher() throws Exception + { + return _session.createProducer(_topic); + } + + MessageProducer createControlPublisher() throws Exception + { + return _session.createProducer(_control); + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java new file mode 100644 index 0000000000..c3b19b558a --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Publisher.java @@ -0,0 +1,186 @@ +/* + * + * 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.qpid.topic; + +import javax.jms.*; + +public class Publisher implements MessageListener +{ + private final Object _lock = new Object(); + private final Connection _connection; + private final Session _session; + private final MessageFactory _factory; + private final MessageProducer _publisher; + private int _count; + + Publisher(Connection connection, int size, int ackMode, boolean persistent) throws Exception + { + _connection = connection; + _session = _connection.createSession(false, ackMode); + _factory = new MessageFactory(_session, size); + _publisher = _factory.createTopicPublisher(); + _publisher.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + System.out.println("Publishing " + (persistent ? "persistent" : "non-persistent") + " messages of " + size + " bytes, " + Config.getAckModeDescription(ackMode) + "."); + } + + private void test(Config config) throws Exception + { + test(config.getBatch(), config.getDelay(), config.getMessages(), config.getClients(), config.getWarmup()); + } + + private void test(int batches, long delay, int msgCount, int consumerCount, int warmup) throws Exception + { + _factory.createControlConsumer().setMessageListener(this); + _connection.start(); + + if (warmup > 0) + { + System.out.println("Runing warmup (" + warmup + " msgs)"); + long time = batch(warmup, consumerCount); + System.out.println("Warmup completed in " + time + "ms"); + } + + long[] times = new long[batches]; + for (int i = 0; i < batches; i++) + { + if (i > 0) + { + Thread.sleep(delay * 1000); + } + times[i] = batch(msgCount, consumerCount); + System.out.println("Batch " + (i + 1) + " of " + batches + " completed in " + times[i] + " ms."); + } + + long min = min(times); + long max = max(times); + System.out.println("min: " + min + ", max: " + max + " avg: " + avg(times, min, max)); + + //request shutdown + _publisher.send(_factory.createShutdownMessage()); + + _connection.stop(); + _connection.close(); + } + + private long batch(int msgCount, int consumerCount) throws Exception + { + _count = consumerCount; + long start = System.currentTimeMillis(); + publish(msgCount); + waitForCompletion(consumerCount); + return System.currentTimeMillis() - start; + } + + private void publish(int count) throws Exception + { + + //send events + for (int i = 0; i < count; i++) + { + _publisher.send(_factory.createEventMessage()); + if ((i + 1) % 100 == 0) + { + System.out.println("Sent " + (i + 1) + " messages"); + } + } + + //request report + _publisher.send(_factory.createReportRequestMessage()); + } + + private void waitForCompletion(int consumers) throws Exception + { + System.out.println("Waiting for completion..."); + synchronized (_lock) + { + while (_count > 0) + { + _lock.wait(); + } + } + } + + + public void onMessage(Message message) + { + System.out.println("Received report " + _factory.getReport(message) + " " + --_count + " remaining"); + if (_count == 0) + { + synchronized (_lock) + { + _lock.notify(); + } + } + } + + static long min(long[] times) + { + long min = times.length > 0 ? times[0] : 0; + for (int i = 0; i < times.length; i++) + { + min = Math.min(min, times[i]); + } + return min; + } + + static long max(long[] times) + { + long max = times.length > 0 ? times[0] : 0; + for (int i = 0; i < times.length; i++) + { + max = Math.max(max, times[i]); + } + return max; + } + + static long avg(long[] times, long min, long max) + { + long sum = 0; + for (int i = 0; i < times.length; i++) + { + sum += times[i]; + } + + int adjustment = 0; + + // Remove min and max if we have run enough batches. + if (times.length > 2) + { + sum -= min; + sum -= max; + adjustment = 2; + } + + return (sum / (times.length - adjustment)); + } + + public static void main(String[] argv) throws Exception + { + Config config = new Config(); + config.setOptions(argv); + + Connection con = config.createConnection(); + int size = config.getPayload(); + int ackMode = config.getAckMode(); + boolean persistent = config.usePersistentMessages(); + new Publisher(con, size, ackMode, persistent).test(config); + } +} -- cgit v1.2.1 From e32debe1df7d0a837e30cd937fb7a18fc5cfa203 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Thu, 24 Apr 2008 17:49:03 +0000 Subject: QPID-832 : Fix eol-style git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@651325 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/ping/PingClient.java | 214 +- .../org/apache/qpid/ping/PingDurableClient.java | 904 ++--- .../org/apache/qpid/ping/PingLatencyTestPerf.java | 622 ++-- .../org/apache/qpid/ping/PingSendOnlyClient.java | 186 +- .../java/org/apache/qpid/ping/PingTestPerf.java | 392 +-- .../apache/qpid/requestreply/PingPongBouncer.java | 906 +++--- .../apache/qpid/requestreply/PingPongProducer.java | 3440 ++++++++++---------- .../apache/qpid/requestreply/PingPongTestPerf.java | 502 +-- .../qpid/test/testcases/MessageThroughputPerf.java | 398 +-- 9 files changed, 3782 insertions(+), 3782 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java index b9632eee4c..0afec83b19 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java @@ -1,107 +1,107 @@ -/* - * - * 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.qpid.ping; - -import org.apache.log4j.Logger; - -import org.apache.qpid.requestreply.PingPongProducer; - -import javax.jms.Destination; - -import java.util.List; -import java.util.Properties; - -/** - * PingClient is a {@link PingPongProducer} that does not need a {@link org.apache.qpid.requestreply.PingPongBouncer} - * to send replies to its pings. It simply listens to its own ping destinations, rather than seperate reply queues. - * It is an all in one ping client, that produces and consumes its own pings. - * - *

    The constructor increments a count of the number of ping clients created. It is assumed that where many - * are created they will all be run in parallel and be active in sending and consuming pings at the same time. - * If the unique destinations flag is not set and a pub/sub ping cycle is being run, this means that they will all hear - * pings sent by each other. The expected number of pings received will therefore be multiplied up by the number of - * active ping clients. The {@link #getConsumersPerDestination()} method is used to supply this multiplier under these - * conditions. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Create a ping producer that listens to its own pings {@link PingPongProducer} - *
    Count the number of ping producers and produce multiplier for scaling up messages expected over topic pings. - *
    - */ -public class PingClient extends PingPongProducer -{ - /** Used for debugging. */ - private final Logger log = Logger.getLogger(PingClient.class); - - /** Used to count the number of ping clients created. */ - private static int _pingClientCount; - - /** - * Creates a ping producer with the specified parameters, of which there are many. See the class level comments - * for {@link PingPongProducer} for details. This constructor creates a connection to the broker and creates - * producer and consumer sessions on it, to send and recieve its pings and replies on. - * - * @param overrides Properties containing any desired overrides to the defaults. - * - * @throws Exception Any exceptions are allowed to fall through. - */ - public PingClient(Properties overrides) throws Exception - { - super(overrides); - - _pingClientCount++; - } - - /** - * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the - * effect of making this pinger listen to its own pings. - * - * @return The ping destinations. - */ - public List getReplyDestinations() - { - return _pingDestinations; - } - - /** - * Supplies the multiplier for the number of ping clients that will hear each ping when doing pub/sub pinging. - * - * @return The scaling up of the number of expected pub/sub pings. - */ - public int getConsumersPerDestination() - { - log.debug("public int getConsumersPerDestination(): called"); - - if (_isUnique) - { - log.debug(_noOfConsumers + " consumer per destination."); - - return _noOfConsumers; - } - else - { - log.debug((_pingClientCount * _noOfConsumers) + " consumers per destination."); - - return _pingClientCount * _noOfConsumers; - } - } -} +/* + * + * 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.qpid.ping; + +import org.apache.log4j.Logger; + +import org.apache.qpid.requestreply.PingPongProducer; + +import javax.jms.Destination; + +import java.util.List; +import java.util.Properties; + +/** + * PingClient is a {@link PingPongProducer} that does not need a {@link org.apache.qpid.requestreply.PingPongBouncer} + * to send replies to its pings. It simply listens to its own ping destinations, rather than seperate reply queues. + * It is an all in one ping client, that produces and consumes its own pings. + * + *

    The constructor increments a count of the number of ping clients created. It is assumed that where many + * are created they will all be run in parallel and be active in sending and consuming pings at the same time. + * If the unique destinations flag is not set and a pub/sub ping cycle is being run, this means that they will all hear + * pings sent by each other. The expected number of pings received will therefore be multiplied up by the number of + * active ping clients. The {@link #getConsumersPerDestination()} method is used to supply this multiplier under these + * conditions. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Create a ping producer that listens to its own pings {@link PingPongProducer} + *
    Count the number of ping producers and produce multiplier for scaling up messages expected over topic pings. + *
    + */ +public class PingClient extends PingPongProducer +{ + /** Used for debugging. */ + private final Logger log = Logger.getLogger(PingClient.class); + + /** Used to count the number of ping clients created. */ + private static int _pingClientCount; + + /** + * Creates a ping producer with the specified parameters, of which there are many. See the class level comments + * for {@link PingPongProducer} for details. This constructor creates a connection to the broker and creates + * producer and consumer sessions on it, to send and recieve its pings and replies on. + * + * @param overrides Properties containing any desired overrides to the defaults. + * + * @throws Exception Any exceptions are allowed to fall through. + */ + public PingClient(Properties overrides) throws Exception + { + super(overrides); + + _pingClientCount++; + } + + /** + * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the + * effect of making this pinger listen to its own pings. + * + * @return The ping destinations. + */ + public List getReplyDestinations() + { + return _pingDestinations; + } + + /** + * Supplies the multiplier for the number of ping clients that will hear each ping when doing pub/sub pinging. + * + * @return The scaling up of the number of expected pub/sub pings. + */ + public int getConsumersPerDestination() + { + log.debug("public int getConsumersPerDestination(): called"); + + if (_isUnique) + { + log.debug(_noOfConsumers + " consumer per destination."); + + return _noOfConsumers; + } + else + { + log.debug((_pingClientCount * _noOfConsumers) + " consumers per destination."); + + return _pingClientCount * _noOfConsumers; + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java index 0c8c19243a..a15897c82b 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java @@ -1,452 +1,452 @@ -/* - * - * 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.qpid.ping; - -import org.apache.log4j.Logger; - -import org.apache.qpid.requestreply.PingPongProducer; -import org.apache.qpid.util.CommandLineParser; - -import org.apache.qpid.junit.extensions.util.MathUtils; -import org.apache.qpid.junit.extensions.util.ParsedProperties; - -import javax.jms.*; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * PingDurableClient is a variation of the {@link PingPongProducer} ping tool. Instead of sending its pings and - * receiving replies to them at the same time, this tool sends pings until it is signalled by some 'event' to stop - * sending. It then waits for another signal before it re-opens a fresh connection and attempts to receive all of the - * pings that it has succesfully sent. It is intended to be an interactive test that lets a user experiment with - * failure conditions when using durable messaging. - * - *

    The events that can stop it from sending are input from the user on the console, failure of its connection to - * the broker, completion of sending a specified number of messages, or expiry of a specified duration. In all cases - * it will do its best to clean up and close the connection before opening a fresh connection to receive the pings - * with. - * - *

    The event to re-connect and attempt to recieve the pings is input from the user on the console. - * - *

    This ping client inherits the configuration properties of its parent class ({@link PingPongProducer}) and - * additionally accepts the following parameters: - * - *

    - *
    Parameters
    Parameter Default Comments - *
    numMessages 100 The total number of messages to send. - *
    numMessagesToAction -1 The number of messages to send before taking a custom 'action'. - *
    duration 30S The length of time to ping for. (Format dDhHmMsS, for d days, h hours, - * m minutes and s seconds). - *
    - * - *

    This ping client also overrides some of the defaults of its parent class, to provide a reasonable set up - * when no parameters are specified. - * - *

    - *
    Parameters
    Parameter Default Comments - *
    uniqueDests false Prevents destination names being timestamped. - *
    transacted true Only makes sense to test with transactions. - *
    persistent true Only makes sense to test persistent. - *
    durableDests true Should use durable queues with persistent messages. - *
    commitBatchSize 10 - *
    rate 20 Total default test time is 5 seconds. - *
    - * - *

    When a number of messages or duration is specified, this ping client will ping until the first of those limits - * is reached. Reaching the limit will be interpreted as the first signal to stop sending, and the ping client will - * wait for the second signal before receiving its pings. - * - *

    This class provides a mechanism for extensions to add arbitrary actions, after a particular number of messages - * have been sent. When the number of messages equal the value set in the 'numMessagesToAction' property is method, - * the {@link #takeAction} method is called. By default this does nothing, but extensions of this class can provide - * custom behaviour with alternative implementations of this method (for example taking a backup). - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Send and receive pings. - *
    Accept user input to signal stop sending. - *
    Accept user input to signal start receiving. - *
    Provide feedback on pings sent versus pings received. - *
    Provide extension point for arbitrary action on a particular message count. - *
    - */ -public class PingDurableClient extends PingPongProducer implements ExceptionListener -{ - private static final Logger log = Logger.getLogger(PingDurableClient.class); - - public static final String NUM_MESSAGES_PROPNAME = "numMessages"; - public static final String NUM_MESSAGES_DEFAULT = "100"; - public static final String DURATION_PROPNAME = "duration"; - public static final String DURATION_DEFAULT = "30S"; - public static final String NUM_MESSAGES_TO_ACTION_PROPNAME = "numMessagesToAction"; - public static final String NUM_MESSAGES_TO_ACTION_DEFAULT = "-1"; - - /** The maximum length of time to wait whilst receiving pings before assuming that no more are coming. */ - private static final long TIME_OUT = 3000; - - static - { - defaults.setProperty(NUM_MESSAGES_PROPNAME, NUM_MESSAGES_DEFAULT); - defaults.setProperty(DURATION_PROPNAME, DURATION_DEFAULT); - defaults.setProperty(UNIQUE_DESTS_PROPNAME, "false"); - defaults.setProperty(TRANSACTED_PROPNAME, "true"); - defaults.setProperty(PERSISTENT_MODE_PROPNAME, "true"); - defaults.setProperty(TX_BATCH_SIZE_PROPNAME, "10"); - defaults.setProperty(RATE_PROPNAME, "20"); - defaults.setProperty(DURABLE_DESTS_PROPNAME, "true"); - defaults.setProperty(NUM_MESSAGES_TO_ACTION_PROPNAME, NUM_MESSAGES_TO_ACTION_DEFAULT); - } - - /** Specifies the number of pings to send, if larger than 0. 0 means send until told to stop. */ - private int numMessages; - - /** Holds the number of messages to send before taking triggering the action. */ - private int numMessagesToAction; - - /** Sepcifies how long to ping for, if larger than 0. 0 means send until told to stop. */ - private long duration; - - /** Used to indciate that this application should terminate. Set by the shutdown hook. */ - private boolean terminate = false; - - /** - * @throws Exception Any exceptions are allowed to fall through. - */ - public PingDurableClient(Properties overrides) throws Exception - { - super(overrides); - log.debug("public PingDurableClient(Properties overrides = " + overrides + "): called"); - - // Extract the additional configuration parameters. - ParsedProperties properties = new ParsedProperties(defaults); - properties.putAll(overrides); - - numMessages = properties.getPropertyAsInteger(NUM_MESSAGES_PROPNAME); - String durationSpec = properties.getProperty(DURATION_PROPNAME); - numMessagesToAction = properties.getPropertyAsInteger(NUM_MESSAGES_TO_ACTION_PROPNAME); - - if (durationSpec != null) - { - duration = MathUtils.parseDuration(durationSpec) * 1000000; - } - } - - /** - * Starts the ping/wait/receive process. - * - * @param args The command line arguments. - */ - public static void main(String[] args) - { - try - { - // Create a ping producer overriding its defaults with all options passed on the command line. - Properties options = - CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); - PingDurableClient pingProducer = new PingDurableClient(options); - - // Create a shutdown hook to terminate the ping-pong producer. - Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); - - // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. - // pingProducer.getConnection().setExceptionListener(pingProducer); - - // Run the test procedure. - int sent = pingProducer.send(); - pingProducer.closeConnection(); - pingProducer.waitForUser("Press return to begin receiving the pings."); - pingProducer.receive(sent); - - System.exit(0); - } - catch (Exception e) - { - System.err.println(e.getMessage()); - log.error("Top level handler caught execption.", e); - System.exit(1); - } - } - - /** - * Performs the main test procedure implemented by this ping client. See the class level comment for details. - */ - protected int send() throws Exception - { - log.debug("public void sendWaitReceive(): called"); - - log.debug("duration = " + duration); - log.debug("numMessages = " + numMessages); - - if (duration > 0) - { - System.out.println("Sending for up to " + (duration / 1000000000f) + " seconds."); - } - - if (_rate > 0) - { - System.out.println("Sending at " + _rate + " messages per second."); - } - - if (numMessages > 0) - { - System.out.println("Sending up to " + numMessages + " messages."); - } - - // Establish the connection and the message producer. - establishConnection(true, false); - _connection.start(); - - Message message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent); - - // Send pings until a terminating condition is received. - boolean endCondition = false; - int messagesSent = 0; - int messagesCommitted = 0; - int messagesNotCommitted = 0; - long start = System.nanoTime(); - - // Clear console in. - clearConsole(); - - while (!endCondition) - { - boolean committed = false; - - try - { - committed = sendMessage(messagesSent, message) && _transacted; - - messagesSent++; - messagesNotCommitted++; - - // Keep count of the number of messsages currently committed and pending commit. - if (committed) - { - log.debug("Adding " + messagesNotCommitted + " messages to the committed count."); - messagesCommitted += messagesNotCommitted; - messagesNotCommitted = 0; - - System.out.println("Commited: " + messagesCommitted); - } - } - catch (JMSException e) - { - log.debug("Got JMSException whilst sending."); - _publish = false; - } - - // Perform the arbitrary action if the number of messages sent has reached the right number. - if (messagesSent == numMessagesToAction) - { - System.out.println("At action point, Messages sent = " + messagesSent + ", Messages Committed = " - + messagesCommitted + ", Messages not Committed = " + messagesNotCommitted); - takeAction(); - } - - // Determine if the end condition has been met, based on the number of messages, time passed, errors on - // the connection or user input. - long now = System.nanoTime(); - - if ((duration != 0) && ((now - start) > duration)) - { - System.out.println("Send halted because duration expired."); - endCondition = true; - } - else if ((numMessages != 0) && (messagesSent >= numMessages)) - { - System.out.println("Send halted because # messages completed."); - endCondition = true; - } - else if (System.in.available() > 0) - { - System.out.println("Send halted by user input."); - endCondition = true; - - clearConsole(); - } - else if (!_publish) - { - System.out.println("Send halted by error on the connection."); - endCondition = true; - } - } - - log.debug("messagesSent = " + messagesSent); - log.debug("messagesCommitted = " + messagesCommitted); - log.debug("messagesNotCommitted = " + messagesNotCommitted); - - System.out.println("Messages sent: " + messagesSent + ", Messages Committed = " + messagesCommitted - + ", Messages not Committed = " + messagesNotCommitted); - - return messagesSent; - } - - protected void closeConnection() - { - // Clean up the connection. - try - { - close(); - } - catch (JMSException e) - { - log.debug("There was an error whilst closing the connection: " + e, e); - System.out.println("There was an error whilst closing the connection."); - - // Ignore as did best could manage to clean up. - } - } - - protected void receive(int messagesSent) throws Exception - { - // Re-establish the connection and the message consumer. - _queueJVMSequenceID = new AtomicInteger(); - _queueSharedID = new AtomicInteger(); - - establishConnection(false, true); - _consumer[0].setMessageListener(null); - _consumerConnection[0].start(); - - // Try to receive all of the pings that were successfully sent. - int messagesReceived = 0; - boolean endCondition = false; - - while (!endCondition) - { - // Message received = _consumer.receiveNoWait(); - Message received = _consumer[0].receive(TIME_OUT); - log.debug("received = " + received); - - if (received != null) - { - messagesReceived++; - } - - // Determine if the end condition has been met, based on the number of messages and time passed since last - // receiving a message. - if (received == null) - { - System.out.println("Timed out."); - endCondition = true; - } - else if (messagesReceived >= messagesSent) - { - System.out.println("Got all messages."); - endCondition = true; - } - } - - // Ensure messages received are committed. - if (_consTransacted) - { - try - { - _consumerSession[0].commit(); - System.out.println("Committed for all messages received."); - } - catch (JMSException e) - { - log.debug("Error during commit: " + e, e); - System.out.println("Error during commit."); - try - { - _consumerSession[0].rollback(); - System.out.println("Rolled back on all messages received."); - } - catch (JMSException e2) - { - log.debug("Error during rollback: " + e, e); - System.out.println("Error on roll back of all messages received."); - } - - } - } - - log.debug("messagesReceived = " + messagesReceived); - - System.out.println("Messages received: " + messagesReceived); - - // Clean up the connection. - close(); - } - - /** - * Clears any pending input from the console. - */ - private void clearConsole() - { - try - { - BufferedReader bis = new BufferedReader(new InputStreamReader(System.in)); - - // System.in.skip(System.in.available()); - while (bis.ready()) - { - bis.readLine(); - } - } - catch (IOException e) - { } - } - - /** - * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the - * effect of making this pinger listen to its own pings. - * - * @return The ping destinations. - */ - public List getReplyDestinations() - { - return _pingDestinations; - } - - /** - * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered with - * the runtime system as a shutdown hook. This shutdown hook sets an additional terminate flag, compared with the - * shutdown hook in {@link PingPongProducer}, because the publish flag is used to indicate that sending or receiving - * message should stop, not that the application should termiante. - * - * @return A shutdown hook for the ping loop. - */ - public Thread getShutdownHook() - { - return new Thread(new Runnable() - { - public void run() - { - stop(); - terminate = true; - } - }); - } - - /** - * Performs an aribtrary action once the 'numMesagesToAction' count is reached on sending messages. This default - * implementation does nothing. - */ - public void takeAction() - { } -} +/* + * + * 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.qpid.ping; + +import org.apache.log4j.Logger; + +import org.apache.qpid.requestreply.PingPongProducer; +import org.apache.qpid.util.CommandLineParser; + +import org.apache.qpid.junit.extensions.util.MathUtils; +import org.apache.qpid.junit.extensions.util.ParsedProperties; + +import javax.jms.*; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * PingDurableClient is a variation of the {@link PingPongProducer} ping tool. Instead of sending its pings and + * receiving replies to them at the same time, this tool sends pings until it is signalled by some 'event' to stop + * sending. It then waits for another signal before it re-opens a fresh connection and attempts to receive all of the + * pings that it has succesfully sent. It is intended to be an interactive test that lets a user experiment with + * failure conditions when using durable messaging. + * + *

    The events that can stop it from sending are input from the user on the console, failure of its connection to + * the broker, completion of sending a specified number of messages, or expiry of a specified duration. In all cases + * it will do its best to clean up and close the connection before opening a fresh connection to receive the pings + * with. + * + *

    The event to re-connect and attempt to recieve the pings is input from the user on the console. + * + *

    This ping client inherits the configuration properties of its parent class ({@link PingPongProducer}) and + * additionally accepts the following parameters: + * + *

    + *
    Parameters
    Parameter Default Comments + *
    numMessages 100 The total number of messages to send. + *
    numMessagesToAction -1 The number of messages to send before taking a custom 'action'. + *
    duration 30S The length of time to ping for. (Format dDhHmMsS, for d days, h hours, + * m minutes and s seconds). + *
    + * + *

    This ping client also overrides some of the defaults of its parent class, to provide a reasonable set up + * when no parameters are specified. + * + *

    + *
    Parameters
    Parameter Default Comments + *
    uniqueDests false Prevents destination names being timestamped. + *
    transacted true Only makes sense to test with transactions. + *
    persistent true Only makes sense to test persistent. + *
    durableDests true Should use durable queues with persistent messages. + *
    commitBatchSize 10 + *
    rate 20 Total default test time is 5 seconds. + *
    + * + *

    When a number of messages or duration is specified, this ping client will ping until the first of those limits + * is reached. Reaching the limit will be interpreted as the first signal to stop sending, and the ping client will + * wait for the second signal before receiving its pings. + * + *

    This class provides a mechanism for extensions to add arbitrary actions, after a particular number of messages + * have been sent. When the number of messages equal the value set in the 'numMessagesToAction' property is method, + * the {@link #takeAction} method is called. By default this does nothing, but extensions of this class can provide + * custom behaviour with alternative implementations of this method (for example taking a backup). + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Send and receive pings. + *
    Accept user input to signal stop sending. + *
    Accept user input to signal start receiving. + *
    Provide feedback on pings sent versus pings received. + *
    Provide extension point for arbitrary action on a particular message count. + *
    + */ +public class PingDurableClient extends PingPongProducer implements ExceptionListener +{ + private static final Logger log = Logger.getLogger(PingDurableClient.class); + + public static final String NUM_MESSAGES_PROPNAME = "numMessages"; + public static final String NUM_MESSAGES_DEFAULT = "100"; + public static final String DURATION_PROPNAME = "duration"; + public static final String DURATION_DEFAULT = "30S"; + public static final String NUM_MESSAGES_TO_ACTION_PROPNAME = "numMessagesToAction"; + public static final String NUM_MESSAGES_TO_ACTION_DEFAULT = "-1"; + + /** The maximum length of time to wait whilst receiving pings before assuming that no more are coming. */ + private static final long TIME_OUT = 3000; + + static + { + defaults.setProperty(NUM_MESSAGES_PROPNAME, NUM_MESSAGES_DEFAULT); + defaults.setProperty(DURATION_PROPNAME, DURATION_DEFAULT); + defaults.setProperty(UNIQUE_DESTS_PROPNAME, "false"); + defaults.setProperty(TRANSACTED_PROPNAME, "true"); + defaults.setProperty(PERSISTENT_MODE_PROPNAME, "true"); + defaults.setProperty(TX_BATCH_SIZE_PROPNAME, "10"); + defaults.setProperty(RATE_PROPNAME, "20"); + defaults.setProperty(DURABLE_DESTS_PROPNAME, "true"); + defaults.setProperty(NUM_MESSAGES_TO_ACTION_PROPNAME, NUM_MESSAGES_TO_ACTION_DEFAULT); + } + + /** Specifies the number of pings to send, if larger than 0. 0 means send until told to stop. */ + private int numMessages; + + /** Holds the number of messages to send before taking triggering the action. */ + private int numMessagesToAction; + + /** Sepcifies how long to ping for, if larger than 0. 0 means send until told to stop. */ + private long duration; + + /** Used to indciate that this application should terminate. Set by the shutdown hook. */ + private boolean terminate = false; + + /** + * @throws Exception Any exceptions are allowed to fall through. + */ + public PingDurableClient(Properties overrides) throws Exception + { + super(overrides); + log.debug("public PingDurableClient(Properties overrides = " + overrides + "): called"); + + // Extract the additional configuration parameters. + ParsedProperties properties = new ParsedProperties(defaults); + properties.putAll(overrides); + + numMessages = properties.getPropertyAsInteger(NUM_MESSAGES_PROPNAME); + String durationSpec = properties.getProperty(DURATION_PROPNAME); + numMessagesToAction = properties.getPropertyAsInteger(NUM_MESSAGES_TO_ACTION_PROPNAME); + + if (durationSpec != null) + { + duration = MathUtils.parseDuration(durationSpec) * 1000000; + } + } + + /** + * Starts the ping/wait/receive process. + * + * @param args The command line arguments. + */ + public static void main(String[] args) + { + try + { + // Create a ping producer overriding its defaults with all options passed on the command line. + Properties options = + CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); + PingDurableClient pingProducer = new PingDurableClient(options); + + // Create a shutdown hook to terminate the ping-pong producer. + Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); + + // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. + // pingProducer.getConnection().setExceptionListener(pingProducer); + + // Run the test procedure. + int sent = pingProducer.send(); + pingProducer.closeConnection(); + pingProducer.waitForUser("Press return to begin receiving the pings."); + pingProducer.receive(sent); + + System.exit(0); + } + catch (Exception e) + { + System.err.println(e.getMessage()); + log.error("Top level handler caught execption.", e); + System.exit(1); + } + } + + /** + * Performs the main test procedure implemented by this ping client. See the class level comment for details. + */ + protected int send() throws Exception + { + log.debug("public void sendWaitReceive(): called"); + + log.debug("duration = " + duration); + log.debug("numMessages = " + numMessages); + + if (duration > 0) + { + System.out.println("Sending for up to " + (duration / 1000000000f) + " seconds."); + } + + if (_rate > 0) + { + System.out.println("Sending at " + _rate + " messages per second."); + } + + if (numMessages > 0) + { + System.out.println("Sending up to " + numMessages + " messages."); + } + + // Establish the connection and the message producer. + establishConnection(true, false); + _connection.start(); + + Message message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent); + + // Send pings until a terminating condition is received. + boolean endCondition = false; + int messagesSent = 0; + int messagesCommitted = 0; + int messagesNotCommitted = 0; + long start = System.nanoTime(); + + // Clear console in. + clearConsole(); + + while (!endCondition) + { + boolean committed = false; + + try + { + committed = sendMessage(messagesSent, message) && _transacted; + + messagesSent++; + messagesNotCommitted++; + + // Keep count of the number of messsages currently committed and pending commit. + if (committed) + { + log.debug("Adding " + messagesNotCommitted + " messages to the committed count."); + messagesCommitted += messagesNotCommitted; + messagesNotCommitted = 0; + + System.out.println("Commited: " + messagesCommitted); + } + } + catch (JMSException e) + { + log.debug("Got JMSException whilst sending."); + _publish = false; + } + + // Perform the arbitrary action if the number of messages sent has reached the right number. + if (messagesSent == numMessagesToAction) + { + System.out.println("At action point, Messages sent = " + messagesSent + ", Messages Committed = " + + messagesCommitted + ", Messages not Committed = " + messagesNotCommitted); + takeAction(); + } + + // Determine if the end condition has been met, based on the number of messages, time passed, errors on + // the connection or user input. + long now = System.nanoTime(); + + if ((duration != 0) && ((now - start) > duration)) + { + System.out.println("Send halted because duration expired."); + endCondition = true; + } + else if ((numMessages != 0) && (messagesSent >= numMessages)) + { + System.out.println("Send halted because # messages completed."); + endCondition = true; + } + else if (System.in.available() > 0) + { + System.out.println("Send halted by user input."); + endCondition = true; + + clearConsole(); + } + else if (!_publish) + { + System.out.println("Send halted by error on the connection."); + endCondition = true; + } + } + + log.debug("messagesSent = " + messagesSent); + log.debug("messagesCommitted = " + messagesCommitted); + log.debug("messagesNotCommitted = " + messagesNotCommitted); + + System.out.println("Messages sent: " + messagesSent + ", Messages Committed = " + messagesCommitted + + ", Messages not Committed = " + messagesNotCommitted); + + return messagesSent; + } + + protected void closeConnection() + { + // Clean up the connection. + try + { + close(); + } + catch (JMSException e) + { + log.debug("There was an error whilst closing the connection: " + e, e); + System.out.println("There was an error whilst closing the connection."); + + // Ignore as did best could manage to clean up. + } + } + + protected void receive(int messagesSent) throws Exception + { + // Re-establish the connection and the message consumer. + _queueJVMSequenceID = new AtomicInteger(); + _queueSharedID = new AtomicInteger(); + + establishConnection(false, true); + _consumer[0].setMessageListener(null); + _consumerConnection[0].start(); + + // Try to receive all of the pings that were successfully sent. + int messagesReceived = 0; + boolean endCondition = false; + + while (!endCondition) + { + // Message received = _consumer.receiveNoWait(); + Message received = _consumer[0].receive(TIME_OUT); + log.debug("received = " + received); + + if (received != null) + { + messagesReceived++; + } + + // Determine if the end condition has been met, based on the number of messages and time passed since last + // receiving a message. + if (received == null) + { + System.out.println("Timed out."); + endCondition = true; + } + else if (messagesReceived >= messagesSent) + { + System.out.println("Got all messages."); + endCondition = true; + } + } + + // Ensure messages received are committed. + if (_consTransacted) + { + try + { + _consumerSession[0].commit(); + System.out.println("Committed for all messages received."); + } + catch (JMSException e) + { + log.debug("Error during commit: " + e, e); + System.out.println("Error during commit."); + try + { + _consumerSession[0].rollback(); + System.out.println("Rolled back on all messages received."); + } + catch (JMSException e2) + { + log.debug("Error during rollback: " + e, e); + System.out.println("Error on roll back of all messages received."); + } + + } + } + + log.debug("messagesReceived = " + messagesReceived); + + System.out.println("Messages received: " + messagesReceived); + + // Clean up the connection. + close(); + } + + /** + * Clears any pending input from the console. + */ + private void clearConsole() + { + try + { + BufferedReader bis = new BufferedReader(new InputStreamReader(System.in)); + + // System.in.skip(System.in.available()); + while (bis.ready()) + { + bis.readLine(); + } + } + catch (IOException e) + { } + } + + /** + * Returns the ping destinations themselves as the reply destinations for this pinger to listen to. This has the + * effect of making this pinger listen to its own pings. + * + * @return The ping destinations. + */ + public List getReplyDestinations() + { + return _pingDestinations; + } + + /** + * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered with + * the runtime system as a shutdown hook. This shutdown hook sets an additional terminate flag, compared with the + * shutdown hook in {@link PingPongProducer}, because the publish flag is used to indicate that sending or receiving + * message should stop, not that the application should termiante. + * + * @return A shutdown hook for the ping loop. + */ + public Thread getShutdownHook() + { + return new Thread(new Runnable() + { + public void run() + { + stop(); + terminate = true; + } + }); + } + + /** + * Performs an aribtrary action once the 'numMesagesToAction' count is reached on sending messages. This default + * implementation does nothing. + */ + public void takeAction() + { } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java index 215dbcefa3..5ba4004c56 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingLatencyTestPerf.java @@ -1,311 +1,311 @@ -/* - * - * 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.qpid.ping; - -import junit.framework.Test; -import junit.framework.TestSuite; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.requestreply.PingPongProducer; - -import org.apache.qpid.junit.extensions.TimingController; -import org.apache.qpid.junit.extensions.TimingControllerAware; -import org.apache.qpid.junit.extensions.util.ParsedProperties; - -import javax.jms.JMSException; -import javax.jms.Message; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; - -/** - * PingLatencyTestPerf is a performance test that outputs multiple timings from its test method, using the timing - * controller interface supplied by the test runner from a seperate listener thread. It outputs round trip timings for - * individual ping messages rather than for how long a complete batch of messages took to process. It also differs from - * the {@link PingTestPerf} test that it extends because it can output timings as replies are received, rather than - * waiting until all expected replies are received. - * - *

    This test does not output timings for every single ping message, as when running at high volume, writing the test - * log for a vast number of messages would slow the testing down. Instead samples ping latency occasionally. The - * frequency of ping sampling is set using the {@link #TEST_RESULTS_BATCH_SIZE_PROPNAME} property, to override the - * default of every {@link #DEFAULT_TEST_RESULTS_BATCH_SIZE}. - * - *

    The size parameter logged for each individual ping is set to the size of the batch of messages that the - * individual timed ping was taken from, rather than 1 for a single message. This is so that the total throughput - * (messages / time) can be calculated in order to examine the relationship between throughput and latency. - * - *

    CRC Card
    Responsibilities Collaborations
    Send many ping - * messages and output timings for sampled individual pings.
    - */ -public class PingLatencyTestPerf extends PingTestPerf implements TimingControllerAware -{ - private static Logger _logger = Logger.getLogger(PingLatencyTestPerf.class); - - /** Holds the name of the property to get the test results logging batch size. */ - public static final String TEST_RESULTS_BATCH_SIZE_PROPNAME = "batchSize"; - - /** Holds the default test results logging batch size. */ - public static final int DEFAULT_TEST_RESULTS_BATCH_SIZE = 1000; - - /** Used to hold the timing controller passed from the test runner. */ - private TimingController _timingController; - - /** Used to generate unique correlation ids for each test run. */ - private AtomicLong corellationIdGenerator = new AtomicLong(); - - /** - * Holds test specifics by correlation id. This consists of the expected number of messages and the timing - * controler. - */ - private Map perCorrelationIds = - Collections.synchronizedMap(new HashMap()); - - /** Holds the batched results listener, that does logging on batch boundaries. */ - private BatchedResultsListener batchedResultsListener = null; - - /** - * Creates a new asynchronous ping performance test with the specified name. - * - * @param name The test name. - */ - public PingLatencyTestPerf(String name) - { - super(name); - - // Sets up the test parameters with defaults. - ParsedProperties.setSysPropertyIfNull(TEST_RESULTS_BATCH_SIZE_PROPNAME, - Integer.toString(DEFAULT_TEST_RESULTS_BATCH_SIZE)); - } - - /** Compile all the tests into a test suite. */ - public static Test suite() - { - // Build a new test suite - TestSuite suite = new TestSuite("Ping Latency Tests"); - - // Run performance tests in read committed mode. - suite.addTest(new PingLatencyTestPerf("testPingLatency")); - - return suite; - } - - /** - * Accepts a timing controller from the test runner. - * - * @param timingController The timing controller to register mutliple timings with. - */ - public void setTimingController(TimingController timingController) - { - _timingController = timingController; - } - - /** - * Gets the timing controller passed in by the test runner. - * - * @return The timing controller passed in by the test runner. - */ - public TimingController getTimingController() - { - return _timingController; - } - - /** - * Sends the specified number of pings, asynchronously outputs timings on every batch boundary, and waits until all - * replies have been received or a time out occurs before exiting this method. - * - * @param numPings The number of pings to send. - */ - public void testPingLatency(int numPings) throws Exception - { - _logger.debug("public void testPingLatency(int numPings): called"); - - // Ensure that at least one ping was requeusted. - if (numPings == 0) - { - _logger.error("Number of pings requested was zero."); - } - - // Get the per thread test setup to run the test through. - PerThreadSetup perThreadSetup = threadSetup.get(); - PingClient pingClient = perThreadSetup._pingClient; - - // Advance the correlation id of messages to send, to make it unique for this run. - String messageCorrelationId = Long.toString(corellationIdGenerator.incrementAndGet()); - _logger.debug("messageCorrelationId = " + messageCorrelationId); - - // Initialize the count and timing controller for the new correlation id. - PerCorrelationId perCorrelationId = new PerCorrelationId(); - TimingController tc = getTimingController().getControllerForCurrentThread(); - perCorrelationId._tc = tc; - perCorrelationId._expectedCount = numPings; - perCorrelationIds.put(messageCorrelationId, perCorrelationId); - - // Attach the chained message listener to the ping producer to listen asynchronously for the replies to these - // messages. - pingClient.setChainedMessageListener(batchedResultsListener); - - // Generate a sample message of the specified size. - Message msg = - pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0), - testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), - testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); - - // Send the requested number of messages, and wait until they have all been received. - long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); - int numReplies = pingClient.pingAndWaitForReply(msg, numPings, timeout, null); - - // Check that all the replies were received and log a fail if they were not. - if (numReplies < numPings) - { - tc.completeTest(false, 0); - } - - // Remove the chained message listener from the ping producer. - pingClient.removeChainedMessageListener(); - - // Remove the expected count and timing controller for the message correlation id, to ensure they are cleaned up. - perCorrelationIds.remove(messageCorrelationId); - } - - /** Performs test fixture creation on a per thread basis. This will only be called once for each test thread. */ - public void threadSetUp() - { - _logger.debug("public void threadSetUp(): called"); - - try - { - // Call the set up method in the super class. This creates a PingClient pinger. - super.threadSetUp(); - - // Create the chained message listener, only if it has not already been created. This is set up with the - // batch size property, to tell it what batch size to output results on. A synchronized block is used to - // ensure that only one thread creates this. - synchronized (this) - { - if (batchedResultsListener == null) - { - int batchSize = Integer.parseInt(testParameters.getProperty(TEST_RESULTS_BATCH_SIZE_PROPNAME)); - batchedResultsListener = new BatchedResultsListener(batchSize); - } - } - - // Get the set up that the super class created. - PerThreadSetup perThreadSetup = threadSetup.get(); - - // Register the chained message listener on the pinger to do its asynchronous test timings from. - perThreadSetup._pingClient.setChainedMessageListener(batchedResultsListener); - } - catch (Exception e) - { - _logger.warn("There was an exception during per thread setup.", e); - } - } - - /** - * BatchedResultsListener is a {@link org.apache.qpid.requestreply.PingPongProducer.ChainedMessageListener} that can - * be attached to the pinger, in order to receive notifications about every message received and the number - * remaining to be received. Whenever the number remaining crosses a batch size boundary this results listener - * outputs a test timing for the actual number of messages received in the current batch. - */ - private class BatchedResultsListener implements PingPongProducer.ChainedMessageListener - { - /** The test results logging batch size. */ - int _batchSize; - private boolean _strictAMQP; - - /** - * Creates a results listener on the specified batch size. - * - * @param batchSize The batch size to use. - */ - public BatchedResultsListener(int batchSize) - { - _batchSize = batchSize; - _strictAMQP = - Boolean.parseBoolean(System.getProperties().getProperty(AMQSession.STRICT_AMQP, - AMQSession.STRICT_AMQP_DEFAULT)); - } - - /** - * This callback method is called from all of the pingers that this test creates. It uses the correlation id - * from the message to identify the timing controller for the test thread that was responsible for sending those - * messages. - * - * @param message The message. - * @param remainingCount The count of messages remaining to be received with a particular correlation id. - * - * @throws javax.jms.JMSException Any underlying JMSException is allowed to fall through. - */ - public void onMessage(Message message, int remainingCount, long latency) throws JMSException - { - _logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount + "): called"); - - // Check if a batch boundary has been crossed. - if ((remainingCount % _batchSize) == 0) - { - // Extract the correlation id from the message. - String correlationId = message.getJMSCorrelationID(); - - // Get the details for the correlation id and check that they are not null. They can become null - // if a test times out. - PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationId); - if (perCorrelationId != null) - { - // Get the timing controller and expected count for this correlation id. - TimingController tc = perCorrelationId._tc; - int expected = perCorrelationId._expectedCount; - - // Calculate how many messages were actually received in the last batch. This will be the batch size - // except where the number expected is not a multiple of the batch size and this is the first remaining - // count to cross a batch size boundary, in which case it will be the number expected modulo the batch - // size. - int receivedInBatch = ((expected - remainingCount) < _batchSize) ? (expected % _batchSize) : _batchSize; - - // Register a test result for the correlation id. - try - { - tc.completeTest(true, receivedInBatch, latency); - } - catch (InterruptedException e) - { - // Ignore this. It means the test runner wants to stop as soon as possible. - _logger.warn("Got InterruptedException.", e); - } - } - // Else ignore, test timed out. Should log a fail here? - } - } - } - - /** - * Holds state specific to each correlation id, needed to output test results. This consists of the count of the - * total expected number of messages, and the timing controller for the thread sending those message ids. - */ - private static class PerCorrelationId - { - public int _expectedCount; - public TimingController _tc; - } -} +/* + * + * 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.qpid.ping; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.requestreply.PingPongProducer; + +import org.apache.qpid.junit.extensions.TimingController; +import org.apache.qpid.junit.extensions.TimingControllerAware; +import org.apache.qpid.junit.extensions.util.ParsedProperties; + +import javax.jms.JMSException; +import javax.jms.Message; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +/** + * PingLatencyTestPerf is a performance test that outputs multiple timings from its test method, using the timing + * controller interface supplied by the test runner from a seperate listener thread. It outputs round trip timings for + * individual ping messages rather than for how long a complete batch of messages took to process. It also differs from + * the {@link PingTestPerf} test that it extends because it can output timings as replies are received, rather than + * waiting until all expected replies are received. + * + *

    This test does not output timings for every single ping message, as when running at high volume, writing the test + * log for a vast number of messages would slow the testing down. Instead samples ping latency occasionally. The + * frequency of ping sampling is set using the {@link #TEST_RESULTS_BATCH_SIZE_PROPNAME} property, to override the + * default of every {@link #DEFAULT_TEST_RESULTS_BATCH_SIZE}. + * + *

    The size parameter logged for each individual ping is set to the size of the batch of messages that the + * individual timed ping was taken from, rather than 1 for a single message. This is so that the total throughput + * (messages / time) can be calculated in order to examine the relationship between throughput and latency. + * + *

    CRC Card
    Responsibilities Collaborations
    Send many ping + * messages and output timings for sampled individual pings.
    + */ +public class PingLatencyTestPerf extends PingTestPerf implements TimingControllerAware +{ + private static Logger _logger = Logger.getLogger(PingLatencyTestPerf.class); + + /** Holds the name of the property to get the test results logging batch size. */ + public static final String TEST_RESULTS_BATCH_SIZE_PROPNAME = "batchSize"; + + /** Holds the default test results logging batch size. */ + public static final int DEFAULT_TEST_RESULTS_BATCH_SIZE = 1000; + + /** Used to hold the timing controller passed from the test runner. */ + private TimingController _timingController; + + /** Used to generate unique correlation ids for each test run. */ + private AtomicLong corellationIdGenerator = new AtomicLong(); + + /** + * Holds test specifics by correlation id. This consists of the expected number of messages and the timing + * controler. + */ + private Map perCorrelationIds = + Collections.synchronizedMap(new HashMap()); + + /** Holds the batched results listener, that does logging on batch boundaries. */ + private BatchedResultsListener batchedResultsListener = null; + + /** + * Creates a new asynchronous ping performance test with the specified name. + * + * @param name The test name. + */ + public PingLatencyTestPerf(String name) + { + super(name); + + // Sets up the test parameters with defaults. + ParsedProperties.setSysPropertyIfNull(TEST_RESULTS_BATCH_SIZE_PROPNAME, + Integer.toString(DEFAULT_TEST_RESULTS_BATCH_SIZE)); + } + + /** Compile all the tests into a test suite. */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Ping Latency Tests"); + + // Run performance tests in read committed mode. + suite.addTest(new PingLatencyTestPerf("testPingLatency")); + + return suite; + } + + /** + * Accepts a timing controller from the test runner. + * + * @param timingController The timing controller to register mutliple timings with. + */ + public void setTimingController(TimingController timingController) + { + _timingController = timingController; + } + + /** + * Gets the timing controller passed in by the test runner. + * + * @return The timing controller passed in by the test runner. + */ + public TimingController getTimingController() + { + return _timingController; + } + + /** + * Sends the specified number of pings, asynchronously outputs timings on every batch boundary, and waits until all + * replies have been received or a time out occurs before exiting this method. + * + * @param numPings The number of pings to send. + */ + public void testPingLatency(int numPings) throws Exception + { + _logger.debug("public void testPingLatency(int numPings): called"); + + // Ensure that at least one ping was requeusted. + if (numPings == 0) + { + _logger.error("Number of pings requested was zero."); + } + + // Get the per thread test setup to run the test through. + PerThreadSetup perThreadSetup = threadSetup.get(); + PingClient pingClient = perThreadSetup._pingClient; + + // Advance the correlation id of messages to send, to make it unique for this run. + String messageCorrelationId = Long.toString(corellationIdGenerator.incrementAndGet()); + _logger.debug("messageCorrelationId = " + messageCorrelationId); + + // Initialize the count and timing controller for the new correlation id. + PerCorrelationId perCorrelationId = new PerCorrelationId(); + TimingController tc = getTimingController().getControllerForCurrentThread(); + perCorrelationId._tc = tc; + perCorrelationId._expectedCount = numPings; + perCorrelationIds.put(messageCorrelationId, perCorrelationId); + + // Attach the chained message listener to the ping producer to listen asynchronously for the replies to these + // messages. + pingClient.setChainedMessageListener(batchedResultsListener); + + // Generate a sample message of the specified size. + Message msg = + pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0), + testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), + testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); + + // Send the requested number of messages, and wait until they have all been received. + long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); + int numReplies = pingClient.pingAndWaitForReply(msg, numPings, timeout, null); + + // Check that all the replies were received and log a fail if they were not. + if (numReplies < numPings) + { + tc.completeTest(false, 0); + } + + // Remove the chained message listener from the ping producer. + pingClient.removeChainedMessageListener(); + + // Remove the expected count and timing controller for the message correlation id, to ensure they are cleaned up. + perCorrelationIds.remove(messageCorrelationId); + } + + /** Performs test fixture creation on a per thread basis. This will only be called once for each test thread. */ + public void threadSetUp() + { + _logger.debug("public void threadSetUp(): called"); + + try + { + // Call the set up method in the super class. This creates a PingClient pinger. + super.threadSetUp(); + + // Create the chained message listener, only if it has not already been created. This is set up with the + // batch size property, to tell it what batch size to output results on. A synchronized block is used to + // ensure that only one thread creates this. + synchronized (this) + { + if (batchedResultsListener == null) + { + int batchSize = Integer.parseInt(testParameters.getProperty(TEST_RESULTS_BATCH_SIZE_PROPNAME)); + batchedResultsListener = new BatchedResultsListener(batchSize); + } + } + + // Get the set up that the super class created. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Register the chained message listener on the pinger to do its asynchronous test timings from. + perThreadSetup._pingClient.setChainedMessageListener(batchedResultsListener); + } + catch (Exception e) + { + _logger.warn("There was an exception during per thread setup.", e); + } + } + + /** + * BatchedResultsListener is a {@link org.apache.qpid.requestreply.PingPongProducer.ChainedMessageListener} that can + * be attached to the pinger, in order to receive notifications about every message received and the number + * remaining to be received. Whenever the number remaining crosses a batch size boundary this results listener + * outputs a test timing for the actual number of messages received in the current batch. + */ + private class BatchedResultsListener implements PingPongProducer.ChainedMessageListener + { + /** The test results logging batch size. */ + int _batchSize; + private boolean _strictAMQP; + + /** + * Creates a results listener on the specified batch size. + * + * @param batchSize The batch size to use. + */ + public BatchedResultsListener(int batchSize) + { + _batchSize = batchSize; + _strictAMQP = + Boolean.parseBoolean(System.getProperties().getProperty(AMQSession.STRICT_AMQP, + AMQSession.STRICT_AMQP_DEFAULT)); + } + + /** + * This callback method is called from all of the pingers that this test creates. It uses the correlation id + * from the message to identify the timing controller for the test thread that was responsible for sending those + * messages. + * + * @param message The message. + * @param remainingCount The count of messages remaining to be received with a particular correlation id. + * + * @throws javax.jms.JMSException Any underlying JMSException is allowed to fall through. + */ + public void onMessage(Message message, int remainingCount, long latency) throws JMSException + { + _logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount + "): called"); + + // Check if a batch boundary has been crossed. + if ((remainingCount % _batchSize) == 0) + { + // Extract the correlation id from the message. + String correlationId = message.getJMSCorrelationID(); + + // Get the details for the correlation id and check that they are not null. They can become null + // if a test times out. + PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationId); + if (perCorrelationId != null) + { + // Get the timing controller and expected count for this correlation id. + TimingController tc = perCorrelationId._tc; + int expected = perCorrelationId._expectedCount; + + // Calculate how many messages were actually received in the last batch. This will be the batch size + // except where the number expected is not a multiple of the batch size and this is the first remaining + // count to cross a batch size boundary, in which case it will be the number expected modulo the batch + // size. + int receivedInBatch = ((expected - remainingCount) < _batchSize) ? (expected % _batchSize) : _batchSize; + + // Register a test result for the correlation id. + try + { + tc.completeTest(true, receivedInBatch, latency); + } + catch (InterruptedException e) + { + // Ignore this. It means the test runner wants to stop as soon as possible. + _logger.warn("Got InterruptedException.", e); + } + } + // Else ignore, test timed out. Should log a fail here? + } + } + } + + /** + * Holds state specific to each correlation id, needed to output test results. This consists of the count of the + * total expected number of messages, and the timing controller for the thread sending those message ids. + */ + private static class PerCorrelationId + { + public int _expectedCount; + public TimingController _tc; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java index 2879f0c322..04e723069a 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java @@ -1,93 +1,93 @@ -/* - * - * 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.qpid.ping; - -import java.util.Properties; - -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.ObjectMessage; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.message.TestMessageFactory; -import org.apache.qpid.util.CommandLineParser; - -/** - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    - */ -public class PingSendOnlyClient extends PingDurableClient -{ - private static final Logger log = Logger.getLogger(PingSendOnlyClient.class); - - public PingSendOnlyClient(Properties overrides) throws Exception - { - super(overrides); - } - - /** - * Starts the ping/wait/receive process. - * - * @param args The command line arguments. - */ - public static void main(String[] args) - { - try - { - // Create a ping producer overriding its defaults with all options passed on the command line. - Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); - PingSendOnlyClient pingProducer = new PingSendOnlyClient(options); - - // Create a shutdown hook to terminate the ping-pong producer. - Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); - - // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. - // pingProducer.getConnection().setExceptionListener(pingProducer); - - // Run the test procedure. - int sent = pingProducer.send(); - pingProducer.waitForUser("Press return to close connection and quit."); - pingProducer.closeConnection(); - - System.exit(0); - } - catch (Exception e) - { - System.err.println(e.getMessage()); - log.error("Top level handler caught execption.", e); - System.exit(1); - } - } - - public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException - { - Message msg = TestMessageFactory.newTextMessage(_producerSession, messageSize); - - // Timestamp the message in nanoseconds. - msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); - - return msg; - } -} +/* + * + * 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.qpid.ping; + +import java.util.Properties; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.ObjectMessage; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.message.TestMessageFactory; +import org.apache.qpid.util.CommandLineParser; + +/** + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    + */ +public class PingSendOnlyClient extends PingDurableClient +{ + private static final Logger log = Logger.getLogger(PingSendOnlyClient.class); + + public PingSendOnlyClient(Properties overrides) throws Exception + { + super(overrides); + } + + /** + * Starts the ping/wait/receive process. + * + * @param args The command line arguments. + */ + public static void main(String[] args) + { + try + { + // Create a ping producer overriding its defaults with all options passed on the command line. + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); + PingSendOnlyClient pingProducer = new PingSendOnlyClient(options); + + // Create a shutdown hook to terminate the ping-pong producer. + Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); + + // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. + // pingProducer.getConnection().setExceptionListener(pingProducer); + + // Run the test procedure. + int sent = pingProducer.send(); + pingProducer.waitForUser("Press return to close connection and quit."); + pingProducer.closeConnection(); + + System.exit(0); + } + catch (Exception e) + { + System.err.println(e.getMessage()); + log.error("Top level handler caught execption.", e); + System.exit(1); + } + } + + public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException + { + Message msg = TestMessageFactory.newTextMessage(_producerSession, messageSize); + + // Timestamp the message in nanoseconds. + msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); + + return msg; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java index fb071a87fe..94b8ea662e 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java @@ -1,196 +1,196 @@ -/* - * - * 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.qpid.ping; - -import junit.framework.Assert; -import junit.framework.Test; -import junit.framework.TestSuite; - -import org.apache.log4j.Logger; - -import org.apache.qpid.requestreply.PingPongProducer; - -import org.apache.qpid.junit.extensions.AsymptoticTestCase; -import org.apache.qpid.junit.extensions.TestThreadAware; -import org.apache.qpid.junit.extensions.util.ParsedProperties; -import org.apache.qpid.junit.extensions.util.TestContextProperties; - -import javax.jms.*; - -/** - * PingTestPerf is a ping test, that has been written with the intention of being scaled up to run many times - * simultaneously to simluate many clients/producers/connections. - * - *

    A single run of the test using the default JUnit test runner will result in the sending and timing of a single - * full round trip ping. This test may be scaled up using a suitable JUnit test runner. - * - *

    The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a - * temporary queue for replies. This setup is only established once for all the test repeats/threads that may be run, - * except if the connection is lost in which case an attempt to re-establish the setup is made. - * - *

    The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that - * is the name of the temporary queue, fires off a message on the original queue and waits for a response on the - * temporary queue. - * - *

    Configurable test properties: message size, transacted or not, persistent or not. Broker connection details. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    - */ -public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware -{ - private static Logger _logger = Logger.getLogger(PingTestPerf.class); - - /** Thread local to hold the per-thread test setup fields. */ - ThreadLocal threadSetup = new ThreadLocal(); - - /** Holds a property reader to extract the test parameters from. */ - protected ParsedProperties testParameters = - TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/); - - public PingTestPerf(String name) - { - super(name); - - _logger.debug("testParameters = " + testParameters); - } - - /** - * Compile all the tests into a test suite. - * @return The test method testPingOk. - */ - public static Test suite() - { - // Build a new test suite - TestSuite suite = new TestSuite("Ping Performance Tests"); - - // Run performance tests in read committed mode. - suite.addTest(new PingTestPerf("testPingOk")); - - return suite; - } - - public void testPingOk(int numPings) throws Exception - { - if (numPings == 0) - { - Assert.fail("Number of pings requested was zero."); - } - - // Get the per thread test setup to run the test through. - PerThreadSetup perThreadSetup = threadSetup.get(); - - if (perThreadSetup == null) - { - Assert.fail("Could not get per thread test setup, it was null."); - } - - // Generate a sample message. This message is already time stamped and has its reply-to destination set. - Message msg = - perThreadSetup._pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0), - testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), - testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); - - // start the test - long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); - int numReplies = perThreadSetup._pingClient.pingAndWaitForReply(msg, numPings, timeout, null); - - // Fail the test if the timeout was exceeded. - if (numReplies != perThreadSetup._pingClient.getExpectedNumPings(numPings)) - { - Assert.fail("The ping timed out after " + timeout + " ms. Messages Sent = " + numPings + ", MessagesReceived = " - + numReplies); - } - } - - /** - * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. - */ - public void threadSetUp() - { - _logger.debug("public void threadSetUp(): called"); - - try - { - PerThreadSetup perThreadSetup = new PerThreadSetup(); - - // This is synchronized because there is a race condition, which causes one connection to sleep if - // all threads try to create connection concurrently. - synchronized (this) - { - // Establish a client to ping a Destination and listen the reply back from same Destination - perThreadSetup._pingClient = new PingClient(testParameters); - perThreadSetup._pingClient.establishConnection(true, true); - } - // Start the client connection - perThreadSetup._pingClient.start(); - - // Attach the per-thread set to the thread. - threadSetup.set(perThreadSetup); - } - catch (Exception e) - { - _logger.warn("There was an exception during per thread setup.", e); - } - } - - /** - * Performs test fixture clean - */ - public void threadTearDown() - { - _logger.debug("public void threadTearDown(): called"); - - try - { - // Get the per thread test fixture. - PerThreadSetup perThreadSetup = threadSetup.get(); - - // Close the pingers so that it cleans up its connection cleanly. - synchronized (this) - { - if ((perThreadSetup != null) && (perThreadSetup._pingClient != null)) - { - perThreadSetup._pingClient.close(); - } - } - } - catch (JMSException e) - { - _logger.warn("There was an exception during per thread tear down."); - } - finally - { - // Ensure the per thread fixture is reclaimed. - threadSetup.remove(); - } - } - - protected static class PerThreadSetup - { - /** - * Holds the test ping client. - */ - protected PingClient _pingClient; - protected String _correlationId; - } -} +/* + * + * 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.qpid.ping; + +import junit.framework.Assert; +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +import org.apache.qpid.requestreply.PingPongProducer; + +import org.apache.qpid.junit.extensions.AsymptoticTestCase; +import org.apache.qpid.junit.extensions.TestThreadAware; +import org.apache.qpid.junit.extensions.util.ParsedProperties; +import org.apache.qpid.junit.extensions.util.TestContextProperties; + +import javax.jms.*; + +/** + * PingTestPerf is a ping test, that has been written with the intention of being scaled up to run many times + * simultaneously to simluate many clients/producers/connections. + * + *

    A single run of the test using the default JUnit test runner will result in the sending and timing of a single + * full round trip ping. This test may be scaled up using a suitable JUnit test runner. + * + *

    The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a + * temporary queue for replies. This setup is only established once for all the test repeats/threads that may be run, + * except if the connection is lost in which case an attempt to re-establish the setup is made. + * + *

    The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that + * is the name of the temporary queue, fires off a message on the original queue and waits for a response on the + * temporary queue. + * + *

    Configurable test properties: message size, transacted or not, persistent or not. Broker connection details. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    + */ +public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware +{ + private static Logger _logger = Logger.getLogger(PingTestPerf.class); + + /** Thread local to hold the per-thread test setup fields. */ + ThreadLocal threadSetup = new ThreadLocal(); + + /** Holds a property reader to extract the test parameters from. */ + protected ParsedProperties testParameters = + TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/); + + public PingTestPerf(String name) + { + super(name); + + _logger.debug("testParameters = " + testParameters); + } + + /** + * Compile all the tests into a test suite. + * @return The test method testPingOk. + */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Ping Performance Tests"); + + // Run performance tests in read committed mode. + suite.addTest(new PingTestPerf("testPingOk")); + + return suite; + } + + public void testPingOk(int numPings) throws Exception + { + if (numPings == 0) + { + Assert.fail("Number of pings requested was zero."); + } + + // Get the per thread test setup to run the test through. + PerThreadSetup perThreadSetup = threadSetup.get(); + + if (perThreadSetup == null) + { + Assert.fail("Could not get per thread test setup, it was null."); + } + + // Generate a sample message. This message is already time stamped and has its reply-to destination set. + Message msg = + perThreadSetup._pingClient.getTestMessage(perThreadSetup._pingClient.getReplyDestinations().get(0), + testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), + testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); + + // start the test + long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); + int numReplies = perThreadSetup._pingClient.pingAndWaitForReply(msg, numPings, timeout, null); + + // Fail the test if the timeout was exceeded. + if (numReplies != perThreadSetup._pingClient.getExpectedNumPings(numPings)) + { + Assert.fail("The ping timed out after " + timeout + " ms. Messages Sent = " + numPings + ", MessagesReceived = " + + numReplies); + } + } + + /** + * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. + */ + public void threadSetUp() + { + _logger.debug("public void threadSetUp(): called"); + + try + { + PerThreadSetup perThreadSetup = new PerThreadSetup(); + + // This is synchronized because there is a race condition, which causes one connection to sleep if + // all threads try to create connection concurrently. + synchronized (this) + { + // Establish a client to ping a Destination and listen the reply back from same Destination + perThreadSetup._pingClient = new PingClient(testParameters); + perThreadSetup._pingClient.establishConnection(true, true); + } + // Start the client connection + perThreadSetup._pingClient.start(); + + // Attach the per-thread set to the thread. + threadSetup.set(perThreadSetup); + } + catch (Exception e) + { + _logger.warn("There was an exception during per thread setup.", e); + } + } + + /** + * Performs test fixture clean + */ + public void threadTearDown() + { + _logger.debug("public void threadTearDown(): called"); + + try + { + // Get the per thread test fixture. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Close the pingers so that it cleans up its connection cleanly. + synchronized (this) + { + if ((perThreadSetup != null) && (perThreadSetup._pingClient != null)) + { + perThreadSetup._pingClient.close(); + } + } + } + catch (JMSException e) + { + _logger.warn("There was an exception during per thread tear down."); + } + finally + { + // Ensure the per thread fixture is reclaimed. + threadSetup.remove(); + } + } + + protected static class PerThreadSetup + { + /** + * Holds the test ping client. + */ + protected PingClient _pingClient; + protected String _correlationId; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java index 0712557383..8e010ccf07 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongBouncer.java @@ -1,453 +1,453 @@ -/* - * - * 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.qpid.requestreply; - -import java.io.IOException; -import java.net.InetAddress; -import java.text.SimpleDateFormat; -import java.util.Date; - -import javax.jms.*; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.jms.ConnectionListener; -import org.apache.qpid.jms.Session; -import org.apache.qpid.topic.Config; -import org.apache.qpid.exchange.ExchangeDefaults; - -/** - * PingPongBouncer is a message listener the bounces back messages to their reply to destination. This is used to return - * ping messages generated by {@link org.apache.qpid.requestreply.PingPongProducer} but could be used for other purposes - * too. - * - *

    The correlation id from the received message is extracted, and placed into the reply as the correlation id. Messages - * are bounced back to their reply-to destination. The original sender of the message has the option to use either a unique - * temporary queue or the correlation id to correlate the original message to the reply. - * - *

    There is a verbose mode flag which causes information about each ping to be output to the console - * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should - * be disabled for real timing tests as writing to the console will slow things down. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Bounce back messages to their reply to destination. - *
    Provide command line invocation to start the bounce back on a configurable broker url. - *
    - * - * @todo Replace the command line parsing with a neater tool. - * - * @todo Make verbose accept a number of messages, only prints to console every X messages. - */ -public class PingPongBouncer implements MessageListener -{ - private static final Logger _logger = Logger.getLogger(PingPongBouncer.class); - - /** The default prefetch size for the message consumer. */ - private static final int PREFETCH = 1; - - /** The default no local flag for the message consumer. */ - private static final boolean NO_LOCAL = true; - - private static final String DEFAULT_DESTINATION_NAME = "ping"; - - /** The default exclusive flag for the message consumer. */ - private static final boolean EXCLUSIVE = false; - - /** A convenient formatter to use when time stamping output. */ - protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); - - /** Used to indicate that the reply generator should log timing info to the console (logger info level). */ - private boolean _verbose = false; - - /** Determines whether this bounce back client bounces back messages persistently. */ - private boolean _persistent = false; - - private Destination _consumerDestination; - - /** Keeps track of the response destination of the previous message for the last reply to producer cache. */ - private Destination _lastResponseDest; - - /** The producer for sending replies with. */ - private MessageProducer _replyProducer; - - /** The consumer controlSession. */ - private Session _consumerSession; - - /** The producer controlSession. */ - private Session _producerSession; - - /** Holds the connection to the broker. */ - private AMQConnection _connection; - - /** Flag used to indicate if this is a point to point or pub/sub ping client. */ - private boolean _isPubSub = false; - - /** - * This flag is used to indicate that the user should be prompted to kill a broker, in order to test - * failover, immediately before committing a transaction. - */ - protected boolean _failBeforeCommit = false; - - /** - * This flag is used to indicate that the user should be prompted to a kill a broker, in order to test - * failover, immediate after committing a transaction. - */ - protected boolean _failAfterCommit = false; - - /** - * Creates a PingPongBouncer on the specified producer and consumer sessions. - * - * @param brokerDetails The addresses of the brokers to connect to. - * @param username The broker username. - * @param password The broker password. - * @param virtualpath The virtual host name within the broker. - * @param destinationName The name of the queue to receive pings on - * (or root of the queue name where many queues are generated). - * @param persistent A flag to indicate that persistent message should be used. - * @param transacted A flag to indicate that pings should be sent within transactions. - * @param selector A message selector to filter received pings with. - * @param verbose A flag to indicate that message timings should be sent to the console. - * - * @throws Exception All underlying exceptions allowed to fall through. This is only test code... - */ - public PingPongBouncer(String brokerDetails, String username, String password, String virtualpath, - String destinationName, boolean persistent, boolean transacted, String selector, boolean verbose, - boolean pubsub) throws Exception - { - // Create a client id to uniquely identify this client. - InetAddress address = InetAddress.getLocalHost(); - String clientId = address.getHostName() + System.currentTimeMillis(); - _verbose = verbose; - _persistent = persistent; - setPubSub(pubsub); - // Connect to the broker. - setConnection(new AMQConnection(brokerDetails, username, password, clientId, virtualpath)); - _logger.info("Connected with URL:" + getConnection().toURL()); - - // Set up the failover notifier. - getConnection().setConnectionListener(new FailoverNotifier()); - - // Create a controlSession to listen for messages on and one to send replies on, transactional depending on the - // command line option. - _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); - _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); - - // Create the queue to listen for message on. - createConsumerDestination(destinationName); - MessageConsumer consumer = - _consumerSession.createConsumer(_consumerDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); - - // Create a producer for the replies, without a default destination. - _replyProducer = _producerSession.createProducer(null); - _replyProducer.setDisableMessageTimestamp(true); - _replyProducer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - - // Set this up to listen for messages on the queue. - consumer.setMessageListener(this); - } - - /** - * Starts a stand alone ping-pong client running in verbose mode. - * - * @param args - */ - public static void main(String[] args) throws Exception - { - System.out.println("Starting..."); - - // Display help on the command line. - if (args.length == 0) - { - _logger.info("Running test with default values..."); - //usage(); - //System.exit(0); - } - - // Extract all command line parameters. - Config config = new Config(); - config.setOptions(args); - String brokerDetails = config.getHost() + ":" + config.getPort(); - String virtualpath = "test"; - String destinationName = config.getDestination(); - if (destinationName == null) - { - destinationName = DEFAULT_DESTINATION_NAME; - } - - String selector = config.getSelector(); - boolean transacted = config.isTransacted(); - boolean persistent = config.usePersistentMessages(); - boolean pubsub = config.isPubSub(); - boolean verbose = true; - - //String selector = null; - - // Instantiate the ping pong client with the command line options and start it running. - PingPongBouncer pingBouncer = - new PingPongBouncer(brokerDetails, "guest", "guest", virtualpath, destinationName, persistent, transacted, - selector, verbose, pubsub); - pingBouncer.getConnection().start(); - - System.out.println("Waiting..."); - } - - private static void usage() - { - System.err.println("Usage: PingPongBouncer \n" + "-host : broker host\n" + "-port : broker port\n" - + "-destinationname : queue/topic name\n" + "-transacted : (true/false). Default is false\n" - + "-persistent : (true/false). Default is false\n" - + "-pubsub : (true/false). Default is false\n" + "-selector : selector string\n"); - } - - /** - * This is a callback method that is notified of all messages for which this has been registered as a message - * listener on a message consumer. It sends a reply (pong) to all messages it receieves on the reply to - * destination of the message. - * - * @param message The message that triggered this callback. - */ - public void onMessage(Message message) - { - try - { - String messageCorrelationId = message.getJMSCorrelationID(); - if (_verbose) - { - _logger.info(timestampFormatter.format(new Date()) + ": Got ping with correlation id, " - + messageCorrelationId); - } - - // Get the reply to destination from the message and check it is set. - Destination responseDest = message.getJMSReplyTo(); - - if (responseDest == null) - { - _logger.debug("Cannot send reply because reply-to destination is null."); - - return; - } - - // Spew out some timing information if verbose mode is on. - if (_verbose) - { - Long timestamp = message.getLongProperty("timestamp"); - - if (timestamp != null) - { - long diff = System.currentTimeMillis() - timestamp; - _logger.info("Time to bounce point: " + diff); - } - } - - // Correlate the reply to the original. - message.setJMSCorrelationID(messageCorrelationId); - - // Send the receieved message as the pong reply. - _replyProducer.send(responseDest, message); - - if (_verbose) - { - _logger.info(timestampFormatter.format(new Date()) + ": Sent reply with correlation id, " - + messageCorrelationId); - } - - // Commit the transaction if running in transactional mode. - commitTx(_producerSession); - } - catch (JMSException e) - { - _logger.debug("There was a JMSException: " + e.getMessage(), e); - } - } - - /** - * Gets the underlying connection that this ping client is running on. - * - * @return The underlying connection that this ping client is running on. - */ - public AMQConnection getConnection() - { - return _connection; - } - - /** - * Sets the connection that this ping client is using. - * - * @param connection The ping connection. - */ - public void setConnection(AMQConnection connection) - { - this._connection = connection; - } - - /** - * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic. - * - * @param pubsub true if this client is pinging a topic, false if it is pinging a queue. - */ - public void setPubSub(boolean pubsub) - { - _isPubSub = pubsub; - } - - /** - * Checks whether this client is a p2p or pub/sub ping client. - * - * @return true if this client is pinging a topic, false if it is pinging a queue. - */ - public boolean isPubSub() - { - return _isPubSub; - } - - /** - * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not - * a transactional controlSession, this method does nothing. - * - *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the - * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker - * after the commit is applied. - * - * @throws javax.jms.JMSException If the commit fails and then the rollback fails. - */ - protected void commitTx(Session session) throws JMSException - { - if (session.getTransacted()) - { - try - { - if (_failBeforeCommit) - { - _logger.debug("Failing Before Commit"); - doFailover(); - } - - session.commit(); - - if (_failAfterCommit) - { - _logger.debug("Failing After Commit"); - doFailover(); - } - - _logger.debug("Session Commited."); - } - catch (JMSException e) - { - _logger.trace("JMSException on commit:" + e.getMessage(), e); - - try - { - session.rollback(); - _logger.debug("Message rolled back."); - } - catch (JMSException jmse) - { - _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); - - // Both commit and rollback failed. Throw the rollback exception. - throw jmse; - } - } - } - } - - /** - * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block - * until the user supplied some input on the terminal. - * - * @param broker The name of the broker to terminate. - */ - protected void doFailover(String broker) - { - System.out.println("Kill Broker " + broker + " now."); - try - { - System.in.read(); - } - catch (IOException e) - { } - - System.out.println("Continuing."); - } - - /** - * Prompts the user to terminate the broker, in order to test failover functionality. This method will block - * until the user supplied some input on the terminal. - */ - protected void doFailover() - { - System.out.println("Kill Broker now."); - try - { - System.in.read(); - } - catch (IOException e) - { } - - System.out.println("Continuing."); - - } - - private void createConsumerDestination(String name) - { - if (isPubSub()) - { - _consumerDestination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, name); - } - else - { - _consumerDestination = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, name); - } - } - - /** - * A connection listener that logs out any failover complete events. Could do more interesting things with this - * at some point... - */ - public static class FailoverNotifier implements ConnectionListener - { - public void bytesSent(long count) - { } - - public void bytesReceived(long count) - { } - - public boolean preFailover(boolean redirect) - { - return true; - } - - public boolean preResubscribe() - { - return true; - } - - public void failoverComplete() - { - _logger.info("App got failover complete callback."); - } - } -} +/* + * + * 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.qpid.requestreply; + +import java.io.IOException; +import java.net.InetAddress; +import java.text.SimpleDateFormat; +import java.util.Date; + +import javax.jms.*; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.jms.ConnectionListener; +import org.apache.qpid.jms.Session; +import org.apache.qpid.topic.Config; +import org.apache.qpid.exchange.ExchangeDefaults; + +/** + * PingPongBouncer is a message listener the bounces back messages to their reply to destination. This is used to return + * ping messages generated by {@link org.apache.qpid.requestreply.PingPongProducer} but could be used for other purposes + * too. + * + *

    The correlation id from the received message is extracted, and placed into the reply as the correlation id. Messages + * are bounced back to their reply-to destination. The original sender of the message has the option to use either a unique + * temporary queue or the correlation id to correlate the original message to the reply. + * + *

    There is a verbose mode flag which causes information about each ping to be output to the console + * (info level logging, so usually console). This can be helpfull to check the bounce backs are happening but should + * be disabled for real timing tests as writing to the console will slow things down. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Bounce back messages to their reply to destination. + *
    Provide command line invocation to start the bounce back on a configurable broker url. + *
    + * + * @todo Replace the command line parsing with a neater tool. + * + * @todo Make verbose accept a number of messages, only prints to console every X messages. + */ +public class PingPongBouncer implements MessageListener +{ + private static final Logger _logger = Logger.getLogger(PingPongBouncer.class); + + /** The default prefetch size for the message consumer. */ + private static final int PREFETCH = 1; + + /** The default no local flag for the message consumer. */ + private static final boolean NO_LOCAL = true; + + private static final String DEFAULT_DESTINATION_NAME = "ping"; + + /** The default exclusive flag for the message consumer. */ + private static final boolean EXCLUSIVE = false; + + /** A convenient formatter to use when time stamping output. */ + protected static final SimpleDateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); + + /** Used to indicate that the reply generator should log timing info to the console (logger info level). */ + private boolean _verbose = false; + + /** Determines whether this bounce back client bounces back messages persistently. */ + private boolean _persistent = false; + + private Destination _consumerDestination; + + /** Keeps track of the response destination of the previous message for the last reply to producer cache. */ + private Destination _lastResponseDest; + + /** The producer for sending replies with. */ + private MessageProducer _replyProducer; + + /** The consumer controlSession. */ + private Session _consumerSession; + + /** The producer controlSession. */ + private Session _producerSession; + + /** Holds the connection to the broker. */ + private AMQConnection _connection; + + /** Flag used to indicate if this is a point to point or pub/sub ping client. */ + private boolean _isPubSub = false; + + /** + * This flag is used to indicate that the user should be prompted to kill a broker, in order to test + * failover, immediately before committing a transaction. + */ + protected boolean _failBeforeCommit = false; + + /** + * This flag is used to indicate that the user should be prompted to a kill a broker, in order to test + * failover, immediate after committing a transaction. + */ + protected boolean _failAfterCommit = false; + + /** + * Creates a PingPongBouncer on the specified producer and consumer sessions. + * + * @param brokerDetails The addresses of the brokers to connect to. + * @param username The broker username. + * @param password The broker password. + * @param virtualpath The virtual host name within the broker. + * @param destinationName The name of the queue to receive pings on + * (or root of the queue name where many queues are generated). + * @param persistent A flag to indicate that persistent message should be used. + * @param transacted A flag to indicate that pings should be sent within transactions. + * @param selector A message selector to filter received pings with. + * @param verbose A flag to indicate that message timings should be sent to the console. + * + * @throws Exception All underlying exceptions allowed to fall through. This is only test code... + */ + public PingPongBouncer(String brokerDetails, String username, String password, String virtualpath, + String destinationName, boolean persistent, boolean transacted, String selector, boolean verbose, + boolean pubsub) throws Exception + { + // Create a client id to uniquely identify this client. + InetAddress address = InetAddress.getLocalHost(); + String clientId = address.getHostName() + System.currentTimeMillis(); + _verbose = verbose; + _persistent = persistent; + setPubSub(pubsub); + // Connect to the broker. + setConnection(new AMQConnection(brokerDetails, username, password, clientId, virtualpath)); + _logger.info("Connected with URL:" + getConnection().toURL()); + + // Set up the failover notifier. + getConnection().setConnectionListener(new FailoverNotifier()); + + // Create a controlSession to listen for messages on and one to send replies on, transactional depending on the + // command line option. + _consumerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + _producerSession = (Session) getConnection().createSession(transacted, Session.AUTO_ACKNOWLEDGE); + + // Create the queue to listen for message on. + createConsumerDestination(destinationName); + MessageConsumer consumer = + _consumerSession.createConsumer(_consumerDestination, PREFETCH, NO_LOCAL, EXCLUSIVE, selector); + + // Create a producer for the replies, without a default destination. + _replyProducer = _producerSession.createProducer(null); + _replyProducer.setDisableMessageTimestamp(true); + _replyProducer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + // Set this up to listen for messages on the queue. + consumer.setMessageListener(this); + } + + /** + * Starts a stand alone ping-pong client running in verbose mode. + * + * @param args + */ + public static void main(String[] args) throws Exception + { + System.out.println("Starting..."); + + // Display help on the command line. + if (args.length == 0) + { + _logger.info("Running test with default values..."); + //usage(); + //System.exit(0); + } + + // Extract all command line parameters. + Config config = new Config(); + config.setOptions(args); + String brokerDetails = config.getHost() + ":" + config.getPort(); + String virtualpath = "test"; + String destinationName = config.getDestination(); + if (destinationName == null) + { + destinationName = DEFAULT_DESTINATION_NAME; + } + + String selector = config.getSelector(); + boolean transacted = config.isTransacted(); + boolean persistent = config.usePersistentMessages(); + boolean pubsub = config.isPubSub(); + boolean verbose = true; + + //String selector = null; + + // Instantiate the ping pong client with the command line options and start it running. + PingPongBouncer pingBouncer = + new PingPongBouncer(brokerDetails, "guest", "guest", virtualpath, destinationName, persistent, transacted, + selector, verbose, pubsub); + pingBouncer.getConnection().start(); + + System.out.println("Waiting..."); + } + + private static void usage() + { + System.err.println("Usage: PingPongBouncer \n" + "-host : broker host\n" + "-port : broker port\n" + + "-destinationname : queue/topic name\n" + "-transacted : (true/false). Default is false\n" + + "-persistent : (true/false). Default is false\n" + + "-pubsub : (true/false). Default is false\n" + "-selector : selector string\n"); + } + + /** + * This is a callback method that is notified of all messages for which this has been registered as a message + * listener on a message consumer. It sends a reply (pong) to all messages it receieves on the reply to + * destination of the message. + * + * @param message The message that triggered this callback. + */ + public void onMessage(Message message) + { + try + { + String messageCorrelationId = message.getJMSCorrelationID(); + if (_verbose) + { + _logger.info(timestampFormatter.format(new Date()) + ": Got ping with correlation id, " + + messageCorrelationId); + } + + // Get the reply to destination from the message and check it is set. + Destination responseDest = message.getJMSReplyTo(); + + if (responseDest == null) + { + _logger.debug("Cannot send reply because reply-to destination is null."); + + return; + } + + // Spew out some timing information if verbose mode is on. + if (_verbose) + { + Long timestamp = message.getLongProperty("timestamp"); + + if (timestamp != null) + { + long diff = System.currentTimeMillis() - timestamp; + _logger.info("Time to bounce point: " + diff); + } + } + + // Correlate the reply to the original. + message.setJMSCorrelationID(messageCorrelationId); + + // Send the receieved message as the pong reply. + _replyProducer.send(responseDest, message); + + if (_verbose) + { + _logger.info(timestampFormatter.format(new Date()) + ": Sent reply with correlation id, " + + messageCorrelationId); + } + + // Commit the transaction if running in transactional mode. + commitTx(_producerSession); + } + catch (JMSException e) + { + _logger.debug("There was a JMSException: " + e.getMessage(), e); + } + } + + /** + * Gets the underlying connection that this ping client is running on. + * + * @return The underlying connection that this ping client is running on. + */ + public AMQConnection getConnection() + { + return _connection; + } + + /** + * Sets the connection that this ping client is using. + * + * @param connection The ping connection. + */ + public void setConnection(AMQConnection connection) + { + this._connection = connection; + } + + /** + * Sets or clears the pub/sub flag to indiciate whether this client is pinging a queue or a topic. + * + * @param pubsub true if this client is pinging a topic, false if it is pinging a queue. + */ + public void setPubSub(boolean pubsub) + { + _isPubSub = pubsub; + } + + /** + * Checks whether this client is a p2p or pub/sub ping client. + * + * @return true if this client is pinging a topic, false if it is pinging a queue. + */ + public boolean isPubSub() + { + return _isPubSub; + } + + /** + * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not + * a transactional controlSession, this method does nothing. + * + *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the + * commit is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker + * after the commit is applied. + * + * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + */ + protected void commitTx(Session session) throws JMSException + { + if (session.getTransacted()) + { + try + { + if (_failBeforeCommit) + { + _logger.debug("Failing Before Commit"); + doFailover(); + } + + session.commit(); + + if (_failAfterCommit) + { + _logger.debug("Failing After Commit"); + doFailover(); + } + + _logger.debug("Session Commited."); + } + catch (JMSException e) + { + _logger.trace("JMSException on commit:" + e.getMessage(), e); + + try + { + session.rollback(); + _logger.debug("Message rolled back."); + } + catch (JMSException jmse) + { + _logger.trace("JMSE on rollback:" + jmse.getMessage(), jmse); + + // Both commit and rollback failed. Throw the rollback exception. + throw jmse; + } + } + } + } + + /** + * Prompts the user to terminate the named broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + * + * @param broker The name of the broker to terminate. + */ + protected void doFailover(String broker) + { + System.out.println("Kill Broker " + broker + " now."); + try + { + System.in.read(); + } + catch (IOException e) + { } + + System.out.println("Continuing."); + } + + /** + * Prompts the user to terminate the broker, in order to test failover functionality. This method will block + * until the user supplied some input on the terminal. + */ + protected void doFailover() + { + System.out.println("Kill Broker now."); + try + { + System.in.read(); + } + catch (IOException e) + { } + + System.out.println("Continuing."); + + } + + private void createConsumerDestination(String name) + { + if (isPubSub()) + { + _consumerDestination = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, name); + } + else + { + _consumerDestination = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, name); + } + } + + /** + * A connection listener that logs out any failover complete events. Could do more interesting things with this + * at some point... + */ + public static class FailoverNotifier implements ConnectionListener + { + public void bytesSent(long count) + { } + + public void bytesReceived(long count) + { } + + public boolean preFailover(boolean redirect) + { + return true; + } + + public boolean preResubscribe() + { + return true; + } + + public void failoverComplete() + { + _logger.info("App got failover complete callback."); + } + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index f328675488..4d8a736ec8 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -1,1720 +1,1720 @@ -/* - * - * 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.qpid.requestreply; - -import org.apache.log4j.Logger; -import org.apache.log4j.NDC; - -import org.apache.qpid.test.framework.TestUtils; - -import org.apache.qpid.junit.extensions.BatchedThrottle; -import org.apache.qpid.junit.extensions.Throttle; -import org.apache.qpid.junit.extensions.util.CommandLineParser; -import org.apache.qpid.junit.extensions.util.ParsedProperties; - -import javax.jms.*; -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.NamingException; - -import java.io.*; -import java.net.InetAddress; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -/** - * PingPongProducer is a client that sends test messages, and waits for replies to these messages. The replies may - * either be generated by another client (see {@link PingPongBouncer}, or an extension of it may be used that listens - * to its own messages and does not send replies (see {@link org.apache.qpid.ping.PingClient}). The intention of ping - * pong producer is that it is a swiss-army knife test client that makes almost every aspect of its behaviour - * configurable. - * - *

    The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. This - * means that this class has to do some work to correlate pings with pongs; it expectes the original message correlation - * id in the ping to be bounced back in the reply correlation id. - * - *

    This ping tool accepts a vast number of configuration options, all of which are passed in to the constructor. It - * can ping topics or queues; ping multiple destinations; do persistent pings; send messages of any size; do pings within - * transactions; control the number of pings to send in each transaction; limit its sending rate; and perform failover - * testing. A complete list of accepted parameters, default values and comments on their usage is provided here: - * - *

    - *
    Parameters
    Parameter Default Comments - *
    messageSize 0 Message size in bytes. Not including any headers. - *
    destinationName ping The root name to use to generate destination names to ping. - *
    persistent false Determines whether peristent delivery is used. - *
    transacted false Determines whether messages are sent/received in transactions. - *
    broker tcp://localhost:5672 Determines the broker to connect to. - *
    virtualHost test Determines the virtual host to send all ping over. - *
    rate 0 The maximum rate (in hertz) to send messages at. 0 means no limit. - *
    verbose false The verbose flag for debugging. Prints to console on every message. - *
    pubsub false Whether to ping topics or queues. Uses p2p by default. - *
    failAfterCommit false Whether to prompt user to kill broker after a commit batch. - *
    failBeforeCommit false Whether to prompt user to kill broker before a commit batch. - *
    failAfterSend false Whether to prompt user to kill broker after a send. - *
    failBeforeSend false Whether to prompt user to kill broker before a send. - *
    failOnce true Whether to prompt for failover only once. - *
    username guest The username to access the broker with. - *
    password guest The password to access the broker with. - *
    selector null Not used. Defines a message selector to filter pings with. - *
    destinationCount 1 The number of destinations to send pings to. - *
    numConsumers 1 The number of consumers on each destination. - *
    timeout 30000 In milliseconds. The timeout to stop waiting for replies. - *
    commitBatchSize 1 The number of messages per transaction in transactional mode. - *
    uniqueDests true Whether each receivers only listens to one ping destination or all. - *
    durableDests false Whether or not durable destinations are used. - *
    ackMode AUTO_ACK The message acknowledgement mode. Possible values are: - * 0 - SESSION_TRANSACTED - * 1 - AUTO_ACKNOWLEDGE - * 2 - CLIENT_ACKNOWLEDGE - * 3 - DUPS_OK_ACKNOWLEDGE - * 257 - NO_ACKNOWLEDGE - * 258 - PRE_ACKNOWLEDGE - *
    consTransacted false Whether or not consumers use transactions. Defaults to the same value - * as the 'transacted' option if not seperately defined. - *
    consAckMode AUTO_ACK The message acknowledgement mode for consumers. Defaults to the same - * value as 'ackMode' if not seperately defined. - *
    maxPending 0 The maximum size in bytes, of messages sent but not yet received. - * Limits the volume of messages currently buffered on the client - * or broker. Can help scale test clients by limiting amount of buffered - * data to avoid out of memory errors. - *
    - * - *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop - * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so by - * starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is also - * registered to terminate the ping-pong loop cleanly. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Provide a ping and wait for all responses cycle. - *
    Provide command line invocation to loop the ping cycle on a configurable broker url. - *
    - * - * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock pair. - * Obtain read lock on all messages, before decrementing the message count. At the end of the on message method add a - * block that obtains the write lock for the very last message, releases any waiting producer. Means that the last - * message waits until all other messages have been handled before releasing producers but allows messages to be - * processed concurrently, unlike the current synchronized block. - */ -public class PingPongProducer implements Runnable, ExceptionListener -{ - /** Used for debugging. */ - private static final Logger log = Logger.getLogger(PingPongProducer.class); - - /** Holds the name of the property to determine whether of not client id is overridden at connection time. */ - public static final String OVERRIDE_CLIENT_ID_PROPNAME = "overrideClientId"; - - /** Holds the default value of the override client id flag. */ - public static final String OVERRIDE_CLIENT_ID_DEAFULT = "false"; - - /** Holds the name of the property to define the JNDI factory name with. */ - public static final String FACTORY_NAME_PROPNAME = "factoryName"; - - /** Holds the default JNDI name of the connection factory. */ - public static final String FACTORY_NAME_DEAFULT = "local"; - - /** Holds the name of the property to set the JNDI initial context properties with. */ - public static final String FILE_PROPERTIES_PROPNAME = "properties"; - - /** Holds the default file name of the JNDI initial context properties. */ - public static final String FILE_PROPERTIES_DEAFULT = "perftests.properties"; - - /** Holds the name of the property to get the test message size from. */ - public static final String MESSAGE_SIZE_PROPNAME = "messageSize"; - - /** Used to set up a default message size. */ - public static final int MESSAGE_SIZE_DEAFULT = 0; - - /** Holds the name of the property to get the ping queue name from. */ - public static final String PING_QUEUE_NAME_PROPNAME = "destinationName"; - - /** Holds the name of the default destination to send pings on. */ - public static final String PING_QUEUE_NAME_DEFAULT = "ping"; - - /** Holds the name of the property to get the queue name postfix from. */ - public static final String QUEUE_NAME_POSTFIX_PROPNAME = "queueNamePostfix"; - - /** Holds the default queue name postfix value. */ - public static final String QUEUE_NAME_POSTFIX_DEFAULT = ""; - - /** Holds the name of the property to get the test delivery mode from. */ - public static final String PERSISTENT_MODE_PROPNAME = "persistent"; - - /** Holds the message delivery mode to use for the test. */ - public static final boolean PERSISTENT_MODE_DEFAULT = false; - - /** Holds the name of the property to get the test transactional mode from. */ - public static final String TRANSACTED_PROPNAME = "transacted"; - - /** Holds the transactional mode to use for the test. */ - public static final boolean TRANSACTED_DEFAULT = false; - - /** Holds the name of the property to get the test consumer transacted mode from. */ - public static final String CONSUMER_TRANSACTED_PROPNAME = "consTransacted"; - - /** Holds the consumer transactional mode default setting. */ - public static final boolean CONSUMER_TRANSACTED_DEFAULT = false; - - /** Holds the name of the property to get the test broker url from. */ - public static final String BROKER_PROPNAME = "broker"; - - /** Holds the default broker url for the test. */ - public static final String BROKER_DEFAULT = "tcp://localhost:5672"; - - /** Holds the name of the property to get the test broker virtual path. */ - public static final String VIRTUAL_HOST_PROPNAME = "virtualHost"; - - /** Holds the default virtual path for the test. */ - public static final String VIRTUAL_HOST_DEFAULT = ""; - - /** Holds the name of the property to get the message rate from. */ - public static final String RATE_PROPNAME = "rate"; - - /** Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. */ - public static final int RATE_DEFAULT = 0; - - /** Holds the name of the property to get the verbose mode proeprty from. */ - public static final String VERBOSE_PROPNAME = "verbose"; - - /** Holds the default verbose mode. */ - public static final boolean VERBOSE_DEFAULT = false; - - /** Holds the name of the property to get the p2p or pub/sub messaging mode from. */ - public static final String PUBSUB_PROPNAME = "pubsub"; - - /** Holds the pub/sub mode default, true means ping a topic, false means ping a queue. */ - public static final boolean PUBSUB_DEFAULT = false; - - /** Holds the name of the property to get the fail after commit flag from. */ - public static final String FAIL_AFTER_COMMIT_PROPNAME = "failAfterCommit"; - - /** Holds the default failover after commit test flag. */ - public static final boolean FAIL_AFTER_COMMIT_DEFAULT = false; - - /** Holds the name of the proeprty to get the fail before commit flag from. */ - public static final String FAIL_BEFORE_COMMIT_PROPNAME = "failBeforeCommit"; - - /** Holds the default failover before commit test flag. */ - public static final boolean FAIL_BEFORE_COMMIT_DEFAULT = false; - - /** Holds the name of the proeprty to get the fail after send flag from. */ - public static final String FAIL_AFTER_SEND_PROPNAME = "failAfterSend"; - - /** Holds the default failover after send test flag. */ - public static final boolean FAIL_AFTER_SEND_DEFAULT = false; - - /** Holds the name of the property to get the fail before send flag from. */ - public static final String FAIL_BEFORE_SEND_PROPNAME = "failBeforeSend"; - - /** Holds the default failover before send test flag. */ - public static final boolean FAIL_BEFORE_SEND_DEFAULT = false; - - /** Holds the name of the property to get the fail once flag from. */ - public static final String FAIL_ONCE_PROPNAME = "failOnce"; - - /** The default failover once flag, true means only do one failover, false means failover on every commit cycle. */ - public static final boolean FAIL_ONCE_DEFAULT = true; - - /** Holds the name of the property to get the broker access username from. */ - public static final String USERNAME_PROPNAME = "username"; - - /** Holds the default broker log on username. */ - public static final String USERNAME_DEFAULT = "guest"; - - /** Holds the name of the property to get the broker access password from. */ - public static final String PASSWORD_PROPNAME = "password"; - - /** Holds the default broker log on password. */ - public static final String PASSWORD_DEFAULT = "guest"; - - /** Holds the name of the proeprty to get the. */ - public static final String SELECTOR_PROPNAME = "selector"; - - /** Holds the default message selector. */ - public static final String SELECTOR_DEFAULT = ""; - - /** Holds the name of the property to get the destination count from. */ - public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; - - /** Defines the default number of destinations to ping. */ - public static final int DESTINATION_COUNT_DEFAULT = 1; - - /** Holds the name of the property to get the number of consumers per destination from. */ - public static final String NUM_CONSUMERS_PROPNAME = "numConsumers"; - - /** Defines the default number consumers per destination. */ - public static final int NUM_CONSUMERS_DEFAULT = 1; - - /** Holds the name of the property to get the waiting timeout for response messages. */ - public static final String TIMEOUT_PROPNAME = "timeout"; - - /** Default time to wait before assuming that a ping has timed out. */ - public static final long TIMEOUT_DEFAULT = 30000; - - /** Holds the name of the property to get the commit batch size from. */ - public static final String TX_BATCH_SIZE_PROPNAME = "commitBatchSize"; - - /** Defines the default number of pings to send in each transaction when running transactionally. */ - public static final int TX_BATCH_SIZE_DEFAULT = 1; - - /** Holds the name of the property to get the unique destinations flag from. */ - public static final String UNIQUE_DESTS_PROPNAME = "uniqueDests"; - - /** Defines the default value for the unique destinations property. */ - public static final boolean UNIQUE_DESTS_DEFAULT = true; - - /** Holds the name of the property to get the durable destinations flag from. */ - public static final String DURABLE_DESTS_PROPNAME = "durableDests"; - - /** Defines the default value of the durable destinations flag. */ - public static final boolean DURABLE_DESTS_DEFAULT = false; - - /** Holds the name of the proeprty to get the message acknowledgement mode from. */ - public static final String ACK_MODE_PROPNAME = "ackMode"; - - /** Defines the default message acknowledgement mode. */ - public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; - - /** Holds the name of the property to get the consumers message acknowledgement mode from. */ - public static final String CONSUMER_ACK_MODE_PROPNAME = "consAckMode"; - - /** Defines the default consumers message acknowledgement mode. */ - public static final int CONSUMER_ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; - - /** Holds the name of the property to get the maximum pending message size setting from. */ - public static final String MAX_PENDING_PROPNAME = "maxPending"; - - /** Defines the default value for the maximum pending message size setting. 0 means no limit. */ - public static final int MAX_PENDING_DEFAULT = 0; - - /** Defines the default prefetch size to use when consuming messages. */ - public static final int PREFETCH_DEFAULT = 100; - - /** Defines the default value of the no local flag to use when consuming messages. */ - public static final boolean NO_LOCAL_DEFAULT = false; - - /** Defines the default value of the exclusive flag to use when consuming messages. */ - public static final boolean EXCLUSIVE_DEFAULT = false; - - /** Holds the name of the property to store nanosecond timestamps in ping messages with. */ - public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp"; - - /** Holds the default configuration properties. */ - public static ParsedProperties defaults = new ParsedProperties(); - - static - { - defaults.setPropertyIfNull(OVERRIDE_CLIENT_ID_PROPNAME, OVERRIDE_CLIENT_ID_DEAFULT); - defaults.setPropertyIfNull(FILE_PROPERTIES_PROPNAME, FILE_PROPERTIES_DEAFULT); - defaults.setPropertyIfNull(FACTORY_NAME_PROPNAME, FACTORY_NAME_DEAFULT); - defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT); - defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT); - defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT); - defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT); - defaults.setPropertyIfNull(PING_QUEUE_NAME_PROPNAME, PING_QUEUE_NAME_DEFAULT); - defaults.setPropertyIfNull(QUEUE_NAME_POSTFIX_PROPNAME, QUEUE_NAME_POSTFIX_DEFAULT); - defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT); - defaults.setPropertyIfNull(TRANSACTED_PROPNAME, TRANSACTED_DEFAULT); - defaults.setPropertyIfNull(CONSUMER_TRANSACTED_PROPNAME, CONSUMER_TRANSACTED_DEFAULT); - defaults.setPropertyIfNull(PERSISTENT_MODE_PROPNAME, PERSISTENT_MODE_DEFAULT); - defaults.setPropertyIfNull(ACK_MODE_PROPNAME, ACK_MODE_DEFAULT); - defaults.setPropertyIfNull(CONSUMER_ACK_MODE_PROPNAME, CONSUMER_ACK_MODE_DEFAULT); - defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT); - defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT); - defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT); - defaults.setPropertyIfNull(UNIQUE_DESTS_PROPNAME, UNIQUE_DESTS_DEFAULT); - defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT); - defaults.setPropertyIfNull(FAIL_BEFORE_COMMIT_PROPNAME, FAIL_BEFORE_COMMIT_DEFAULT); - defaults.setPropertyIfNull(FAIL_AFTER_COMMIT_PROPNAME, FAIL_AFTER_COMMIT_DEFAULT); - defaults.setPropertyIfNull(FAIL_BEFORE_SEND_PROPNAME, FAIL_BEFORE_SEND_DEFAULT); - defaults.setPropertyIfNull(FAIL_AFTER_SEND_PROPNAME, FAIL_AFTER_SEND_DEFAULT); - defaults.setPropertyIfNull(FAIL_ONCE_PROPNAME, FAIL_ONCE_DEFAULT); - defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT); - defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT); - defaults.setPropertyIfNull(NUM_CONSUMERS_PROPNAME, NUM_CONSUMERS_DEFAULT); - defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT); - defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT); - defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT); - } - - /** Allows setting of client ID on the connection, rather than through the connection URL. */ - protected boolean _overrideClientId; - - /** Holds the JNDI name of the JMS connection factory. */ - protected String _factoryName; - - /** Holds the name of the properties file to configure JNDI with. */ - protected String _fileProperties; - - /** Holds the broker url. */ - protected String _brokerDetails; - - /** Holds the username to access the broker with. */ - protected String _username; - - /** Holds the password to access the broker with. */ - protected String _password; - - /** Holds the virtual host on the broker to run the tests through. */ - protected String _virtualpath; - - /** Holds the root name from which to generate test destination names. */ - protected String _destinationName; - - /** Holds the default queue name postfix value. */ - protected String _queueNamePostfix; - - /** Holds the message selector to filter the pings with. */ - protected String _selector; - - /** Holds the producers transactional mode flag. */ - protected boolean _transacted; - - /** Holds the consumers transactional mode flag. */ - protected boolean _consTransacted; - - /** Determines whether this producer sends persistent messages. */ - protected boolean _persistent; - - /** Holds the acknowledgement mode used for the producers. */ - protected int _ackMode; - - /** Holds the acknowledgement mode setting for the consumers. */ - protected int _consAckMode; - - /** Determines what size of messages this producer sends. */ - protected int _messageSize; - - /** Used to indicate that the ping loop should print out whenever it pings. */ - protected boolean _verbose; - - /** Flag used to indicate if this is a point to point or pub/sub ping client. */ - protected boolean _isPubSub; - - /** Flag used to indicate if the destinations should be unique client. */ - protected boolean _isUnique; - - /** Flag used to indicate that durable destination should be used. */ - protected boolean _isDurable; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ - protected boolean _failBeforeCommit; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ - protected boolean _failAfterCommit; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ - protected boolean _failBeforeSend; - - /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ - protected boolean _failAfterSend; - - /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ - protected boolean _failOnce; - - /** Holds the number of sends that should be performed in every transaction when using transactions. */ - protected int _txBatchSize; - - /** Holds the number of destinations to ping. */ - protected int _noOfDestinations; - - /** Holds the number of consumers per destination. */ - protected int _noOfConsumers; - - /** Holds the maximum send rate in herz. */ - protected int _rate; - - /** - * Holds the size of the maximum amount of pending data that the client should buffer, sending is suspended - * if this limit is breached. - */ - protected int _maxPendingSize; - - /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ - private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); - - /** A source for providing sequential unqiue ids for instances of this class to be identifed with. */ - private static AtomicInteger _instanceIdGenerator = new AtomicInteger(0); - - /** Holds this instances unique id. */ - private int instanceId; - - /** - * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross multiple - * ping producers on the same JVM. - */ - private static Map perCorrelationIds = - Collections.synchronizedMap(new HashMap()); - - /** A convenient formatter to use when time stamping output. */ - protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); - - /** Holds the connection for the message producer. */ - protected Connection _connection; - - /** Holds the consumer connections. */ - protected Connection[] _consumerConnection; - - /** Holds the controlSession on which ping replies are received. */ - protected Session[] _consumerSession; - - /** Holds the producer controlSession, needed to create ping messages. */ - protected Session _producerSession; - - /** Holds the destination where the response messages will arrive. */ - protected Destination _replyDestination; - - /** Holds the set of destinations that this ping producer pings. */ - protected List _pingDestinations; - - /** Used to restrict the sending rate to a specified limit. */ - protected Throttle _rateLimiter; - - /** Holds a message listener that this message listener chains all its messages to. */ - protected ChainedMessageListener _chainedMessageListener = null; - - /** - * This id generator is used to generate ids to append to the queue name to ensure that queues can be unique when - * creating multiple ping producers in the same JVM. - */ - protected static AtomicInteger _queueJVMSequenceID = new AtomicInteger(); - - /** - * This id generator is used to generates ids that are only unique within this pinger. Creating multiple pingers - * on the same JVM using this id generator will allow them to ping on the same queues. - */ - protected AtomicInteger _queueSharedID = new AtomicInteger(); - - /** Used to tell the ping loop when to terminate, it only runs while this is true. */ - protected boolean _publish = true; - - /** Holds the message producer to send the pings through. */ - protected MessageProducer _producer; - - /** Holds the message consumer to receive the ping replies through. */ - protected MessageConsumer[] _consumer; - - /** The prompt to display when asking the user to kill the broker for failover testing. */ - private static final String KILL_BROKER_PROMPT = "Kill broker now, then press Return."; - - /** Holds the name for this test client to be identified to the broker with. */ - private String _clientID; - - /** Keeps count of the total messages sent purely for debugging purposes. */ - private static AtomicInteger numSent = new AtomicInteger(); - - /** - * Holds a monitor which is used to synchronize sender and receivers threads, where the sender has elected - * to wait until the number of unreceived message is reduced before continuing to send. This monitor is a - * fair SynchronousQueue becuase that provides fair scheduling, to ensure that all producer threads get an - * equal chance to produce messages. - */ - static final SynchronousQueue _sendPauseMonitor = new SynchronousQueue(true); - - /** Keeps a count of the number of message currently sent but not received. */ - static AtomicInteger _unreceived = new AtomicInteger(0); - - /** - * Creates a ping producer with the specified parameters, of which there are many. See the class level comments - * for details. This constructor creates a connection to the broker and creates producer and consumer sessions on - * it, to send and recieve its pings and replies on. - * - * @param overrides Properties containing any desired overrides to the defaults. - * - * @throws Exception Any exceptions are allowed to fall through. - */ - public PingPongProducer(Properties overrides) throws Exception - { - // log.debug("public PingPongProducer(Properties overrides = " + overrides + "): called"); - instanceId = _instanceIdGenerator.getAndIncrement(); - - // Create a set of parsed properties from the defaults overriden by the passed in values. - ParsedProperties properties = new ParsedProperties(defaults); - properties.putAll(overrides); - - // Extract the configuration properties to set the pinger up with. - _overrideClientId = properties.getPropertyAsBoolean(OVERRIDE_CLIENT_ID_PROPNAME); - _factoryName = properties.getProperty(FACTORY_NAME_PROPNAME); - _fileProperties = properties.getProperty(FILE_PROPERTIES_PROPNAME); - _brokerDetails = properties.getProperty(BROKER_PROPNAME); - _username = properties.getProperty(USERNAME_PROPNAME); - _password = properties.getProperty(PASSWORD_PROPNAME); - _virtualpath = properties.getProperty(VIRTUAL_HOST_PROPNAME); - _destinationName = properties.getProperty(PING_QUEUE_NAME_PROPNAME); - _queueNamePostfix = properties.getProperty(QUEUE_NAME_POSTFIX_PROPNAME); - _selector = properties.getProperty(SELECTOR_PROPNAME); - _transacted = properties.getPropertyAsBoolean(TRANSACTED_PROPNAME); - _consTransacted = properties.getPropertyAsBoolean(CONSUMER_TRANSACTED_PROPNAME); - _persistent = properties.getPropertyAsBoolean(PERSISTENT_MODE_PROPNAME); - _messageSize = properties.getPropertyAsInteger(MESSAGE_SIZE_PROPNAME); - _verbose = properties.getPropertyAsBoolean(VERBOSE_PROPNAME); - _failAfterCommit = properties.getPropertyAsBoolean(FAIL_AFTER_COMMIT_PROPNAME); - _failBeforeCommit = properties.getPropertyAsBoolean(FAIL_BEFORE_COMMIT_PROPNAME); - _failAfterSend = properties.getPropertyAsBoolean(FAIL_AFTER_SEND_PROPNAME); - _failBeforeSend = properties.getPropertyAsBoolean(FAIL_BEFORE_SEND_PROPNAME); - _failOnce = properties.getPropertyAsBoolean(FAIL_ONCE_PROPNAME); - _txBatchSize = properties.getPropertyAsInteger(TX_BATCH_SIZE_PROPNAME); - _noOfDestinations = properties.getPropertyAsInteger(DESTINATION_COUNT_PROPNAME); - _noOfConsumers = properties.getPropertyAsInteger(NUM_CONSUMERS_PROPNAME); - _rate = properties.getPropertyAsInteger(RATE_PROPNAME); - _isPubSub = properties.getPropertyAsBoolean(PUBSUB_PROPNAME); - _isUnique = properties.getPropertyAsBoolean(UNIQUE_DESTS_PROPNAME); - _isDurable = properties.getPropertyAsBoolean(DURABLE_DESTS_PROPNAME); - _ackMode = _transacted ? 0 : properties.getPropertyAsInteger(ACK_MODE_PROPNAME); - _consAckMode = _consTransacted ? 0 : properties.getPropertyAsInteger(CONSUMER_ACK_MODE_PROPNAME); - _maxPendingSize = properties.getPropertyAsInteger(MAX_PENDING_PROPNAME); - - // Check that one or more destinations were specified. - if (_noOfDestinations < 1) - { - throw new IllegalArgumentException("There must be at least one destination."); - } - - // Set up a throttle to control the send rate, if a rate > 0 is specified. - if (_rate > 0) - { - _rateLimiter = new BatchedThrottle(); - _rateLimiter.setRate(_rate); - } - - // Create the connection and message producers/consumers. - // establishConnection(true, true); - } - - /** - * Establishes a connection to the broker and creates message consumers and producers based on the parameters - * that this ping client was created with. - * - * @param producer Flag to indicate whether or not the producer should be set up. - * @param consumer Flag to indicate whether or not the consumers should be set up. - * - * @throws Exception Any exceptions are allowed to fall through. - */ - public void establishConnection(boolean producer, boolean consumer) throws Exception - { - // log.debug("public void establishConnection(): called"); - - // Generate a unique identifying name for this client, based on it ip address and the current time. - InetAddress address = InetAddress.getLocalHost(); - // _clientID = address.getHostName() + System.currentTimeMillis(); - _clientID = "perftest_" + instanceId; - - // Create a connection to the broker. - createConnection(_clientID); - - // Create transactional or non-transactional sessions, based on the command line arguments. - _producerSession = _connection.createSession(_transacted, _ackMode); - - _consumerSession = new Session[_noOfConsumers]; - - for (int i = 0; i < _noOfConsumers; i++) - { - _consumerSession[i] = _consumerConnection[i].createSession(_consTransacted, _consAckMode); - } - - // Create the destinations to send pings to and receive replies from. - _replyDestination = _consumerSession[0].createTemporaryQueue(); - createPingDestinations(_noOfDestinations, _selector, _destinationName, _isUnique, _isDurable); - - // Create the message producer only if instructed to. - if (producer) - { - createProducer(); - } - - // Create the message consumer only if instructed to. - if (consumer) - { - createReplyConsumers(getReplyDestinations(), _selector); - } - } - - /** - * Establishes a connection to the broker, based on the configuration parameters that this ping client was - * created with. - * - * @param clientID The clients identifier. - * - * @throws JMSException Underlying exceptions allowed to fall through. - * @throws NamingException Underlying exceptions allowed to fall through. - * @throws IOException Underlying exceptions allowed to fall through. - */ - protected void createConnection(String clientID) throws JMSException, NamingException, IOException - { - // _log.debug("protected void createConnection(String clientID = " + clientID + "): called"); - - // _log.debug("Creating a connection for the message producer."); - File propsFile = new File(_fileProperties); - InputStream is = new FileInputStream(propsFile); - Properties properties = new Properties(); - properties.load(is); - - Context context = new InitialContext(properties); - ConnectionFactory factory = (ConnectionFactory) context.lookup(_factoryName); - _connection = factory.createConnection(_username, _password); - - if (_overrideClientId) - { - _connection.setClientID(clientID); - } - - // _log.debug("Creating " + _noOfConsumers + " connections for the consumers."); - - _consumerConnection = new Connection[_noOfConsumers]; - - for (int i = 0; i < _noOfConsumers; i++) - { - _consumerConnection[i] = factory.createConnection(_username, _password); - // _consumerConnection[i].setClientID(clientID); - } - } - - /** - * Starts a ping-pong loop running from the command line. The bounce back client {@link PingPongBouncer} also needs - * to be started to bounce the pings back again. - * - * @param args The command line arguments. - */ - public static void main(String[] args) - { - try - { - Properties options = - CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); - - // Create a ping producer overriding its defaults with all options passed on the command line. - PingPongProducer pingProducer = new PingPongProducer(options); - pingProducer.establishConnection(true, true); - - // Start the ping producers dispatch thread running. - pingProducer._connection.start(); - - // Create a shutdown hook to terminate the ping-pong producer. - Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); - - // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. - pingProducer._connection.setExceptionListener(pingProducer); - - // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. - Thread pingThread = new Thread(pingProducer); - pingThread.run(); - pingThread.join(); - } - catch (Exception e) - { - System.err.println(e.getMessage()); - log.error("Top level handler caught execption.", e); - System.exit(1); - } - } - - /** - * Convenience method for a short pause. - * - * @param sleepTime The time in milliseconds to pause for. - */ - public static void pause(long sleepTime) - { - if (sleepTime > 0) - { - try - { - Thread.sleep(sleepTime); - } - catch (InterruptedException ie) - { } - } - } - - /** - * Gets all the reply destinations (to listen for replies on). In this case this will just be the single reply to - * destination of this pinger. - * - * @return The single reply to destination of this pinger, wrapped in a list. - */ - public List getReplyDestinations() - { - // log.debug("public List getReplyDestinations(): called"); - - List replyDestinations = new ArrayList(); - replyDestinations.add(_replyDestination); - - // log.debug("replyDestinations = " + replyDestinations); - - return replyDestinations; - } - - /** - * Creates the producer to send the pings on. This is created without a default destination. Its persistent delivery - * flag is set accoring the ping producer creation options. - * - * @throws JMSException Any JMSExceptions are allowed to fall through. - */ - public void createProducer() throws JMSException - { - // log.debug("public void createProducer(): called"); - - _producer = (MessageProducer) _producerSession.createProducer(null); - _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); - - // log.debug("Created producer for " + (_persistent ? "persistent" : "non-persistent") + " messages."); - } - - /** - * Creates consumers for the specified number of destinations. The destinations themselves are also created by this - * method. - * - * @param noOfDestinations The number of destinations to create consumers for. - * @param selector The message selector to filter the consumers with. - * @param rootName The root of the name, or actual name if only one is being created. - * @param unique true to make the destinations unique to this pinger, false to share the - * numbering with all pingers on the same JVM. - * @param durable If the destinations are durable topics. - * - * @throws JMSException Any JMSExceptions are allowed to fall through. - */ - public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique, - boolean durable) throws JMSException - { - /*log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " - + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = " - + durable + "): called");*/ - - _pingDestinations = new ArrayList(); - - // Create the desired number of ping destinations and consumers for them. - // log.debug("Creating " + noOfDestinations + " destinations to ping."); - - for (int i = 0; i < noOfDestinations; i++) - { - Destination destination; - String id; - - // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag. - if (unique) - { - // log.debug("Creating unique destinations."); - id = "_" + _queueJVMSequenceID.incrementAndGet() + "_" + _connection.getClientID(); - } - else - { - // log.debug("Creating shared destinations."); - id = "_" + _queueSharedID.incrementAndGet(); - } - - // Check if this is a pub/sub pinger, in which case create topics. - if (_isPubSub) - { - destination = _producerSession.createTopic(rootName + id); - // log.debug("Created non-durable topic " + destination); - - if (durable) - { - _producerSession.createDurableSubscriber((Topic) destination, _connection.getClientID()); - } - } - // Otherwise this is a p2p pinger, in which case create queues. - else - { - destination = _producerSession.createQueue(rootName + id + _queueNamePostfix); - // log.debug("Created queue " + destination); - } - - // Keep the destination. - _pingDestinations.add(destination); - } - } - - /** - * Creates consumers for the specified destinations and registers this pinger to listen to their messages. - * - * @param destinations The destinations to listen to. - * @param selector A selector to filter the messages with. - * - * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through. - */ - public void createReplyConsumers(Collection destinations, String selector) throws JMSException - { - /*log.debug("public void createReplyConsumers(Collection destinations = " + destinations - + ", String selector = " + selector + "): called");*/ - - log.debug("There are " + destinations.size() + " destinations."); - log.debug("Creating " + _noOfConsumers + " consumers on each destination."); - log.debug("Total number of consumers is: " + (destinations.size() * _noOfConsumers)); - - for (Destination destination : destinations) - { - _consumer = new MessageConsumer[_noOfConsumers]; - - for (int i = 0; i < _noOfConsumers; i++) - { - // Create a consumer for the destination and set this pinger to listen to its messages. - _consumer[i] = _consumerSession[i].createConsumer(destination, selector, NO_LOCAL_DEFAULT); - - final int consumerNo = i; - - _consumer[i].setMessageListener(new MessageListener() - { - public void onMessage(Message message) - { - onMessageWithConsumerNo(message, consumerNo); - } - }); - - log.debug("Set consumer " + i + " to listen to replies sent to destination: " + destination); - } - } - } - - /** - * Stores the received message in the replies map, then resets the boolean latch that a thread waiting for a - * correlating reply may be waiting on. This is only done if the reply has a correlation id that is expected in the - * replies map. - * - * @param message The received message. - * @param consumerNo The consumer number within this test pinger instance. - */ - public void onMessageWithConsumerNo(Message message, int consumerNo) - { - // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo = " + consumerNo + "): called"); - try - { - long now = System.nanoTime(); - long timestamp = getTimestamp(message); - long pingTime = now - timestamp; - - // NDC.push("id" + instanceId + "/cons" + consumerNo); - - // Extract the messages correlation id. - String correlationID = message.getJMSCorrelationID(); - // log.debug("correlationID = " + correlationID); - - // int num = message.getIntProperty("MSG_NUM"); - // log.info("Message " + num + " received."); - - boolean isRedelivered = message.getJMSRedelivered(); - // log.debug("isRedelivered = " + isRedelivered); - - if (!isRedelivered) - { - // Countdown on the traffic light if there is one for the matching correlation id. - PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); - - if (perCorrelationId != null) - { - CountDownLatch trafficLight = perCorrelationId.trafficLight; - - // Restart the timeout timer on every message. - perCorrelationId.timeOutStart = System.nanoTime(); - - // log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); - - // Release waiting senders if there are some and using maxPending limit. - if ((_maxPendingSize > 0)) - { - // Decrement the count of sent but not yet received messages. - int unreceived = _unreceived.decrementAndGet(); - int unreceivedSize = - (unreceived * ((_messageSize == 0) ? 1 : _messageSize)) - / (_isPubSub ? getConsumersPerDestination() : 1); - - // log.debug("unreceived = " + unreceived); - // log.debug("unreceivedSize = " + unreceivedSize); - - // synchronized (_sendPauseMonitor) - // { - if (unreceivedSize < _maxPendingSize) - { - _sendPauseMonitor.poll(); - } - // } - } - - // Decrement the countdown latch. Before this point, it is possible that two threads might enter this - // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block - // ensures that each thread will get a unique value for the remaining messages. - long trueCount; - long remainingCount; - - synchronized (trafficLight) - { - trafficLight.countDown(); - - trueCount = trafficLight.getCount(); - remainingCount = trueCount - 1; - - // NDC.push("/rem" + remainingCount); - - // log.debug("remainingCount = " + remainingCount); - // log.debug("trueCount = " + trueCount); - - // Commit on transaction batch size boundaries. At this point in time the waiting producer - // remains blocked, even on the last message. - // Commit count is divided by noOfConsumers in p2p mode, so that each consumer only commits on - // each batch boundary. For pub/sub each consumer gets every message so no division is done. - // When running in client ack mode, an ack is done instead of a commit, on the commit batch - // size boundaries. - long commitCount = _isPubSub ? remainingCount : (remainingCount / _noOfConsumers); - // log.debug("commitCount = " + commitCount); - - if ((commitCount % _txBatchSize) == 0) - { - if (_consAckMode == 2) - { - // log.debug("Doing client ack for consumer " + consumerNo + "."); - message.acknowledge(); - } - else - { - // log.debug("Trying commit for consumer " + consumerNo + "."); - commitTx(_consumerSession[consumerNo]); - // log.info("Tx committed on consumer " + consumerNo); - } - } - - // Forward the message and remaining count to any interested chained message listener. - if (_chainedMessageListener != null) - { - _chainedMessageListener.onMessage(message, (int) remainingCount, pingTime); - } - - // Check if this is the last message, in which case release any waiting producers. This is done - // after the transaction has been committed and any listeners notified. - if (trueCount == 1) - { - trafficLight.countDown(); - } - } - } - else - { - log.warn("Got unexpected message with correlationId: " + correlationID); - } - } - else - { - log.warn("Got redelivered message, ignoring."); - } - } - catch (JMSException e) - { - log.warn("There was a JMSException: " + e.getMessage(), e); - } - finally - { - // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo): ending"); - // NDC.clear(); - } - } - - /** - * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out - * before a reply arrives, then a null reply is returned from this method. This method allows the caller to specify - * the correlation id. - * - * @param message The message to send. If this is null, one is generated. - * @param numPings The number of ping messages to send. - * @param timeout The timeout in milliseconds. - * @param messageCorrelationId The message correlation id. If this is null, one is generated. - * - * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait - * for all prematurely. - * - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - * @throws InterruptedException When interrupted by a timeout - */ - public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) - throws JMSException, InterruptedException - { - /*log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " - + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ - - // Generate a unique correlation id to put on the messages before sending them, if one was not specified. - if (messageCorrelationId == null) - { - messageCorrelationId = Long.toString(_correlationIdGenerator.incrementAndGet()); - } - - try - { - // NDC.push("prod"); - - // Create a count down latch to count the number of replies with. This is created before the messages are - // sent so that the replies cannot be received before the count down is created. - // One is added to this, so that the last reply becomes a special case. The special case is that the - // chained message listener must be called before this sender can be unblocked, but that decrementing the - // countdown needs to be done before the chained listener can be called. - PerCorrelationId perCorrelationId = new PerCorrelationId(); - - perCorrelationId.trafficLight = new CountDownLatch(getExpectedNumPings(numPings) + 1); - perCorrelationIds.put(messageCorrelationId, perCorrelationId); - - // Set up the current time as the start time for pinging on the correlation id. This is used to determine - // timeouts. - perCorrelationId.timeOutStart = System.nanoTime(); - - // Send the specifed number of messages. - pingNoWaitForReply(message, numPings, messageCorrelationId); - - boolean timedOut; - boolean allMessagesReceived; - int numReplies; - - do - { - // Block the current thread until replies to all the messages are received, or it times out. - perCorrelationId.trafficLight.await(timeout, TimeUnit.MILLISECONDS); - - // Work out how many replies were receieved. - numReplies = getExpectedNumPings(numPings) - (int) perCorrelationId.trafficLight.getCount(); - - allMessagesReceived = numReplies == getExpectedNumPings(numPings); - - // log.debug("numReplies = " + numReplies); - // log.debug("allMessagesReceived = " + allMessagesReceived); - - // Recheck the timeout condition. - long now = System.nanoTime(); - long lastMessageReceievedAt = perCorrelationId.timeOutStart; - timedOut = (now - lastMessageReceievedAt) > (timeout * 1000000); - - // log.debug("now = " + now); - // log.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); - } - while (!timedOut && !allMessagesReceived); - - if ((numReplies < getExpectedNumPings(numPings)) && _verbose) - { - log.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); - } - else if (_verbose) - { - log.info("Got all replies on id, " + messageCorrelationId); - } - - // commitTx(_consumerSession); - - // log.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); - - return numReplies; - } - // Ensure that the message countdown latch is always removed from the reply map. The reply map is long lived, - // so will be a memory leak if this is not done. - finally - { - // NDC.pop(); - perCorrelationIds.remove(messageCorrelationId); - } - } - - /** - * Sends the specified number of ping messages and does not wait for correlating replies. - * - * @param message The message to send. - * @param numPings The number of pings to send. - * @param messageCorrelationId A correlation id to place on all messages sent. - * - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - */ - public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException - { - /*log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings - + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ - - if (message == null) - { - message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent); - } - - message.setJMSCorrelationID(messageCorrelationId); - - // Set up a committed flag to detect uncommitted messages at the end of the send loop. This may occurr if the - // transaction batch size is not a factor of the number of pings. In which case an extra commit at the end is - // needed. - boolean committed = false; - - // Send all of the ping messages. - for (int i = 0; i < numPings; i++) - { - // Re-timestamp the message. - // message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); - - // Send the message, passing in the message count. - committed = sendMessage(i, message); - - // Spew out per message timings on every message sonly in verbose mode. - /*if (_verbose) - { - log.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); - }*/ - } - - // Call commit if the send loop finished before reaching a batch size boundary so there may still be uncommitted messages. - if (!committed) - { - commitTx(_producerSession); - } - } - - /** - * Sends the sepcified message, applies rate limiting and possibly commits the current transaction. The count of - * messages sent so far must be specified and is used to round robin the ping destinations (where there are more - * than one), and to determine if the transaction batch size has been reached and the sent messages should be - * committed. - * - * @param i The count of messages sent so far in a loop of multiple calls to this send method. - * @param message The message to send. - * - * @return true if the messages were committed, false otherwise. - * - * @throws JMSException All underlyiung JMSExceptions are allowed to fall through. - */ - protected boolean sendMessage(int i, Message message) throws JMSException - { - try - { - NDC.push("id" + instanceId + "/prod"); - - // log.debug("protected boolean sendMessage(int i = " + i + ", Message message): called"); - // log.debug("_txBatchSize = " + _txBatchSize); - - // Round robin the destinations as the messages are sent. - Destination destination = _pingDestinations.get(i % _pingDestinations.size()); - - // Prompt the user to kill the broker when doing failover testing. - _failBeforeSend = waitForUserToPromptOnFailure(_failBeforeSend); - - // Get the test setup for the correlation id. - String correlationID = message.getJMSCorrelationID(); - PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); - - // If necessary, wait until the max pending message size comes within its limit. - if (_maxPendingSize > 0) - { - synchronized (_sendPauseMonitor) - { - // Used to keep track of the number of times that send has to wait. - int numWaits = 0; - - // The maximum number of waits before the test gives up and fails. This has been chosen to correspond with - // the test timeout. - int waitLimit = (int) (TIMEOUT_DEFAULT / 10000); - - while (true) - { - // Get the size estimate of sent but not yet received messages. - int unreceived = _unreceived.get(); - int unreceivedSize = - (unreceived * ((_messageSize == 0) ? 1 : _messageSize)) - / (_isPubSub ? getConsumersPerDestination() : 1); - - // log.debug("unreceived = " + unreceived); - // log.debug("unreceivedSize = " + unreceivedSize); - // log.debug("_maxPendingSize = " + _maxPendingSize); - - if (unreceivedSize > _maxPendingSize) - { - // log.debug("unreceived size estimate over limit = " + unreceivedSize); - - // Fail the test if the send has had to wait more than the maximum allowed number of times. - if (numWaits > waitLimit) - { - String errorMessage = - "Send has had to wait for the unreceivedSize (" + unreceivedSize - + ") to come below the maxPendingSize (" + _maxPendingSize + ") more that " + waitLimit - + " times."; - log.warn(errorMessage); - throw new RuntimeException(errorMessage); - } - - // Wait on the send pause barrier for the limit to be re-established. - try - { - long start = System.nanoTime(); - // _sendPauseMonitor.wait(10000); - _sendPauseMonitor.offer(new Object(), 10000, TimeUnit.MILLISECONDS); - long end = System.nanoTime(); - - // Count the wait only if it was for > 99% of the requested wait time. - if (((float) (end - start) / (float) (10000 * 1000000L)) > 0.99) - { - numWaits++; - } - } - catch (InterruptedException e) - { - // Restore the interrupted status - Thread.currentThread().interrupt(); - throw new RuntimeException(e); - } - } - else - { - break; - } - } - } - } - - // Send the message either to its round robin destination, or its default destination. - // int num = numSent.incrementAndGet(); - // message.setIntProperty("MSG_NUM", num); - setTimestamp(message); - - if (destination == null) - { - _producer.send(message); - } - else - { - _producer.send(destination, message); - } - - // Increase the unreceived size, this may actually happen after the message is received. - // The unreceived size is incremented by the number of consumers that will get a copy of the message, - // in pub/sub mode. - if (_maxPendingSize > 0) - { - int newUnreceivedCount = _unreceived.addAndGet(_isPubSub ? getConsumersPerDestination() : 1); - // log.debug("newUnreceivedCount = " + newUnreceivedCount); - } - - // Apply message rate throttling if a rate limit has been set up. - if (_rateLimiter != null) - { - _rateLimiter.throttle(); - } - - // Call commit every time the commit batch size is reached. - boolean committed = false; - - // Commit on every transaction batch size boundary. Here i + 1 is the count of actual messages sent. - if (((i + 1) % _txBatchSize) == 0) - { - // log.debug("Trying commit on producer session."); - committed = commitTx(_producerSession); - } - - return committed; - } - finally - { - NDC.clear(); - } - } - - /** - * If the specified fail flag is set, this method waits for the user to cause a failure and then indicate to the - * test that the failure has occurred, before the method returns. - * - * @param failFlag The fail flag to test. - * - * @return The new value for the fail flag. If the {@link #_failOnce} flag is set, then each fail flag is only - * used once, then reset. - */ - private boolean waitForUserToPromptOnFailure(boolean failFlag) - { - if (failFlag) - { - if (_failOnce) - { - failFlag = false; - } - - // log.debug("Failing Before Send"); - waitForUser(KILL_BROKER_PROMPT); - } - - return failFlag; - } - - /** - * Implements a single iteration of the ping loop. This sends the number of pings specified by the transaction batch - * size property, and waits for replies to all of them. Any errors cause the publish flag to be cleared, which will - * terminate the pinger. - */ - public void pingLoop() - { - try - { - // Generate a sample message and time stamp it. - Message msg = getTestMessage(_replyDestination, _messageSize, _persistent); - // setTimestamp(msg); - - // Send the message and wait for a reply. - pingAndWaitForReply(msg, TX_BATCH_SIZE_DEFAULT, TIMEOUT_DEFAULT, null); - } - catch (JMSException e) - { - _publish = false; - // log.debug("There was a JMSException: " + e.getMessage(), e); - } - catch (InterruptedException e) - { - _publish = false; - // log.debug("There was an interruption: " + e.getMessage(), e); - } - } - - /** - * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set - * here. - * - * @param messageListener The chained message listener. - */ - public void setChainedMessageListener(ChainedMessageListener messageListener) - { - _chainedMessageListener = messageListener; - } - - /** Removes any chained message listeners from this pinger. */ - public void removeChainedMessageListener() - { - _chainedMessageListener = null; - } - - /** - * Generates a test message of the specified size, with the specified reply-to destination and persistence flag. - * - * @param replyQueue The reply-to destination for the message. - * @param messageSize The desired size of the message in bytes. - * @param persistent true if the message should use persistent delivery, false otherwise. - * - * @return A freshly generated test message. - * - * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. - */ - public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException - { - // return TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); - return TestUtils.createTestMessageOfSize(_producerSession, messageSize); - } - - /** - * Sets the current time in nanoseconds as the timestamp on the message. - * - * @param msg The message to timestamp. - * - * @throws JMSException Any JMSExceptions are allowed to fall through. - */ - protected void setTimestamp(Message msg) throws JMSException - { - /*if (((AMQSession)_producerSession).isStrictAMQP()) - { - ((AMQMessage)msg).setTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME), System.nanoTime()); - } - else - {*/ - msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); - // } - } - - /** - * Extracts the nanosecond timestamp from a message. - * - * @param msg The message to extract the time stamp from. - * - * @return The timestamp in nanos. - * - * @throws JMSException Any JMSExceptions are allowed to fall through. - */ - protected long getTimestamp(Message msg) throws JMSException - { - /*if (((AMQSession)_producerSession).isStrictAMQP()) - { - Long value = ((AMQMessage)msg).getTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME)); - - return (value == null) ? 0L : value; - } - else - {*/ - return msg.getLongProperty(PingPongProducer.MESSAGE_TIMESTAMP_PROPNAME); - // } - } - - /** - * Stops the ping loop by clearing the publish flag. The current loop will complete when it notices that this flag - * has been cleared. - */ - public void stop() - { - _publish = false; - } - - /** - * Starts the producer and consumer connections. - * - * @throws JMSException Any JMSExceptions are allowed to fall through. - */ - public void start() throws JMSException - { - // log.debug("public void start(): called"); - - _connection.start(); - // log.debug("Producer started."); - - for (int i = 0; i < _noOfConsumers; i++) - { - _consumerConnection[i].start(); - // log.debug("Consumer " + i + " started."); - } - } - - /** Implements a ping loop that repeatedly pings until the publish flag becomes false. */ - public void run() - { - // Keep running until the publish flag is cleared. - while (_publish) - { - pingLoop(); - } - } - - /** - * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the - * connection, this clears the publish flag which in turn will halt the ping loop. - * - * @param e The exception that triggered this callback method. - */ - public void onException(JMSException e) - { - // log.debug("public void onException(JMSException e = " + e + "): called", e); - _publish = false; - } - - /** - * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered - * with the runtime system as a shutdown hook. - * - * @return A shutdown hook for the ping loop. - */ - public Thread getShutdownHook() - { - return new Thread(new Runnable() - { - public void run() - { - stop(); - } - }); - } - - /** - * Closes all of the producer and consumer connections. - * - * @throws JMSException All JMSException are allowed to fall through. - */ - public void close() throws JMSException - { - // log.debug("public void close(): called"); - - try - { - if (_connection != null) - { - // log.debug("Before close producer connection."); - _connection.close(); - // log.debug("Closed producer connection."); - } - - for (int i = 0; i < _noOfConsumers; i++) - { - if (_consumerConnection[i] != null) - { - // log.debug("Before close consumer connection " + i + "."); - _consumerConnection[i].close(); - // log.debug("Closed consumer connection " + i + "."); - } - } - } - finally - { - _connection = null; - _producerSession = null; - _consumerSession = null; - _consumerConnection = null; - _producer = null; - _consumer = null; - _pingDestinations = null; - _replyDestination = null; - } - } - - /** - * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not a - * transactional controlSession, this method does nothing (unless the failover after send flag is set). - * - *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit is - * applied. This flag applies whether the pinger is transactional or not. - * - *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the commit - * is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker after the - * commit is applied. These flags will only apply if using a transactional pinger. - * - * @param session The controlSession to commit - * - * @return true if the controlSession was committed, false if it was not. - * - * @throws javax.jms.JMSException If the commit fails and then the rollback fails. - * - * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit - * method, because commits only apply to transactional pingers, but fail after send applied to transactional and - * non-transactional alike. - */ - protected boolean commitTx(Session session) throws JMSException - { - // log.debug("protected void commitTx(Session session): called"); - - boolean committed = false; - - _failAfterSend = waitForUserToPromptOnFailure(_failAfterSend); - - if (session.getTransacted()) - { - // log.debug("Session is transacted."); - - try - { - _failBeforeCommit = waitForUserToPromptOnFailure(_failBeforeCommit); - - long start = System.nanoTime(); - session.commit(); - committed = true; - // log.debug("Time taken to commit :" + ((System.nanoTime() - start) / 1000000f) + " ms"); - - _failAfterCommit = waitForUserToPromptOnFailure(_failAfterCommit); - - // log.debug("Session Commited."); - } - catch (JMSException e) - { - // log.debug("JMSException on commit:" + e.getMessage(), e); - - try - { - session.rollback(); - // log.debug("Message rolled back."); - } - catch (JMSException jmse) - { - // log.debug("JMSE on rollback:" + jmse.getMessage(), jmse); - - // Both commit and rollback failed. Throw the rollback exception. - throw jmse; - } - } - } - - return committed; - } - - /** - * Outputs a prompt to the console and waits for the user to press return. - * - * @param prompt The prompt to display on the console. - */ - public void waitForUser(String prompt) - { - System.out.println(prompt); - - try - { - System.in.read(); - } - catch (IOException e) - { - // Ignored. - } - - System.out.println("Continuing."); - } - - /** - * Gets the number of consumers that are listening to each destination in the test. - * - * @return int The number of consumers subscribing to each topic. - */ - public int getConsumersPerDestination() - { - return _noOfConsumers; - } - - /** - * Calculates how many pings are expected to be received for the given number sent. - * - * @param numpings The number of pings that will be sent. - * - * @return The number that should be received, for the test to pass. - */ - public int getExpectedNumPings(int numpings) - { - // log.debug("public int getExpectedNumPings(int numpings = " + numpings + "): called"); - - // log.debug("Each ping will be received by " + (_isPubSub ? getConsumersPerDestination() : 1) + " consumers."); - - return numpings * (_isPubSub ? getConsumersPerDestination() : 1); - } - - /** - * Defines a chained message listener interface that can be attached to this pinger. Whenever this pinger's {@link - * PingPongProducer#onMessageWithConsumerNo} method is called, the chained listener set through the {@link - * PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected count of - * messages with that correlation id. - * - *

    Provided only one pinger is producing messages with that correlation id, the chained listener will always be - * given unique message counts. It will always be called while the producer waiting for all messages to arrive is - * still blocked. - */ - public static interface ChainedMessageListener - { - /** - * Notifies interested listeners about message arrival and important test stats, the number of messages - * remaining in the test, and the messages send timestamp. - * - * @param message The newly arrived message. - * @param remainingCount The number of messages left to complete the test. - * @param latency The nanosecond latency of the message. - * - * @throws JMSException Any JMS exceptions is allowed to fall through. - */ - public void onMessage(Message message, int remainingCount, long latency) throws JMSException; - } - - /** - * Holds information on each correlation id. The countdown latch, the current timeout timer... More stuff to be - * added to this: read/write lock to make onMessage more concurrent as described in class header comment. - */ - protected static class PerCorrelationId - { - /** Holds a countdown on number of expected messages. */ - CountDownLatch trafficLight; - - /** Holds the last timestamp that the timeout was reset to. */ - Long timeOutStart; - } -} +/* + * + * 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.qpid.requestreply; + +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; + +import org.apache.qpid.test.framework.TestUtils; + +import org.apache.qpid.junit.extensions.BatchedThrottle; +import org.apache.qpid.junit.extensions.Throttle; +import org.apache.qpid.junit.extensions.util.CommandLineParser; +import org.apache.qpid.junit.extensions.util.ParsedProperties; + +import javax.jms.*; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import java.io.*; +import java.net.InetAddress; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * PingPongProducer is a client that sends test messages, and waits for replies to these messages. The replies may + * either be generated by another client (see {@link PingPongBouncer}, or an extension of it may be used that listens + * to its own messages and does not send replies (see {@link org.apache.qpid.ping.PingClient}). The intention of ping + * pong producer is that it is a swiss-army knife test client that makes almost every aspect of its behaviour + * configurable. + * + *

    The pings are sent with a reply-to field set to a single temporary queue, which is the same for all pings. This + * means that this class has to do some work to correlate pings with pongs; it expectes the original message correlation + * id in the ping to be bounced back in the reply correlation id. + * + *

    This ping tool accepts a vast number of configuration options, all of which are passed in to the constructor. It + * can ping topics or queues; ping multiple destinations; do persistent pings; send messages of any size; do pings within + * transactions; control the number of pings to send in each transaction; limit its sending rate; and perform failover + * testing. A complete list of accepted parameters, default values and comments on their usage is provided here: + * + *

    + *
    Parameters
    Parameter Default Comments + *
    messageSize 0 Message size in bytes. Not including any headers. + *
    destinationName ping The root name to use to generate destination names to ping. + *
    persistent false Determines whether peristent delivery is used. + *
    transacted false Determines whether messages are sent/received in transactions. + *
    broker tcp://localhost:5672 Determines the broker to connect to. + *
    virtualHost test Determines the virtual host to send all ping over. + *
    rate 0 The maximum rate (in hertz) to send messages at. 0 means no limit. + *
    verbose false The verbose flag for debugging. Prints to console on every message. + *
    pubsub false Whether to ping topics or queues. Uses p2p by default. + *
    failAfterCommit false Whether to prompt user to kill broker after a commit batch. + *
    failBeforeCommit false Whether to prompt user to kill broker before a commit batch. + *
    failAfterSend false Whether to prompt user to kill broker after a send. + *
    failBeforeSend false Whether to prompt user to kill broker before a send. + *
    failOnce true Whether to prompt for failover only once. + *
    username guest The username to access the broker with. + *
    password guest The password to access the broker with. + *
    selector null Not used. Defines a message selector to filter pings with. + *
    destinationCount 1 The number of destinations to send pings to. + *
    numConsumers 1 The number of consumers on each destination. + *
    timeout 30000 In milliseconds. The timeout to stop waiting for replies. + *
    commitBatchSize 1 The number of messages per transaction in transactional mode. + *
    uniqueDests true Whether each receivers only listens to one ping destination or all. + *
    durableDests false Whether or not durable destinations are used. + *
    ackMode AUTO_ACK The message acknowledgement mode. Possible values are: + * 0 - SESSION_TRANSACTED + * 1 - AUTO_ACKNOWLEDGE + * 2 - CLIENT_ACKNOWLEDGE + * 3 - DUPS_OK_ACKNOWLEDGE + * 257 - NO_ACKNOWLEDGE + * 258 - PRE_ACKNOWLEDGE + *
    consTransacted false Whether or not consumers use transactions. Defaults to the same value + * as the 'transacted' option if not seperately defined. + *
    consAckMode AUTO_ACK The message acknowledgement mode for consumers. Defaults to the same + * value as 'ackMode' if not seperately defined. + *
    maxPending 0 The maximum size in bytes, of messages sent but not yet received. + * Limits the volume of messages currently buffered on the client + * or broker. Can help scale test clients by limiting amount of buffered + * data to avoid out of memory errors. + *
    + * + *

    This implements the Runnable interface with a run method that implements an infinite ping loop. The ping loop + * does all its work through helper methods, so that code wishing to run a ping-pong cycle is not forced to do so by + * starting a new thread. The command line invocation does take advantage of this ping loop. A shutdown hook is also + * registered to terminate the ping-pong loop cleanly. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Provide a ping and wait for all responses cycle. + *
    Provide command line invocation to loop the ping cycle on a configurable broker url. + *
    + * + * @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock pair. + * Obtain read lock on all messages, before decrementing the message count. At the end of the on message method add a + * block that obtains the write lock for the very last message, releases any waiting producer. Means that the last + * message waits until all other messages have been handled before releasing producers but allows messages to be + * processed concurrently, unlike the current synchronized block. + */ +public class PingPongProducer implements Runnable, ExceptionListener +{ + /** Used for debugging. */ + private static final Logger log = Logger.getLogger(PingPongProducer.class); + + /** Holds the name of the property to determine whether of not client id is overridden at connection time. */ + public static final String OVERRIDE_CLIENT_ID_PROPNAME = "overrideClientId"; + + /** Holds the default value of the override client id flag. */ + public static final String OVERRIDE_CLIENT_ID_DEAFULT = "false"; + + /** Holds the name of the property to define the JNDI factory name with. */ + public static final String FACTORY_NAME_PROPNAME = "factoryName"; + + /** Holds the default JNDI name of the connection factory. */ + public static final String FACTORY_NAME_DEAFULT = "local"; + + /** Holds the name of the property to set the JNDI initial context properties with. */ + public static final String FILE_PROPERTIES_PROPNAME = "properties"; + + /** Holds the default file name of the JNDI initial context properties. */ + public static final String FILE_PROPERTIES_DEAFULT = "perftests.properties"; + + /** Holds the name of the property to get the test message size from. */ + public static final String MESSAGE_SIZE_PROPNAME = "messageSize"; + + /** Used to set up a default message size. */ + public static final int MESSAGE_SIZE_DEAFULT = 0; + + /** Holds the name of the property to get the ping queue name from. */ + public static final String PING_QUEUE_NAME_PROPNAME = "destinationName"; + + /** Holds the name of the default destination to send pings on. */ + public static final String PING_QUEUE_NAME_DEFAULT = "ping"; + + /** Holds the name of the property to get the queue name postfix from. */ + public static final String QUEUE_NAME_POSTFIX_PROPNAME = "queueNamePostfix"; + + /** Holds the default queue name postfix value. */ + public static final String QUEUE_NAME_POSTFIX_DEFAULT = ""; + + /** Holds the name of the property to get the test delivery mode from. */ + public static final String PERSISTENT_MODE_PROPNAME = "persistent"; + + /** Holds the message delivery mode to use for the test. */ + public static final boolean PERSISTENT_MODE_DEFAULT = false; + + /** Holds the name of the property to get the test transactional mode from. */ + public static final String TRANSACTED_PROPNAME = "transacted"; + + /** Holds the transactional mode to use for the test. */ + public static final boolean TRANSACTED_DEFAULT = false; + + /** Holds the name of the property to get the test consumer transacted mode from. */ + public static final String CONSUMER_TRANSACTED_PROPNAME = "consTransacted"; + + /** Holds the consumer transactional mode default setting. */ + public static final boolean CONSUMER_TRANSACTED_DEFAULT = false; + + /** Holds the name of the property to get the test broker url from. */ + public static final String BROKER_PROPNAME = "broker"; + + /** Holds the default broker url for the test. */ + public static final String BROKER_DEFAULT = "tcp://localhost:5672"; + + /** Holds the name of the property to get the test broker virtual path. */ + public static final String VIRTUAL_HOST_PROPNAME = "virtualHost"; + + /** Holds the default virtual path for the test. */ + public static final String VIRTUAL_HOST_DEFAULT = ""; + + /** Holds the name of the property to get the message rate from. */ + public static final String RATE_PROPNAME = "rate"; + + /** Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. */ + public static final int RATE_DEFAULT = 0; + + /** Holds the name of the property to get the verbose mode proeprty from. */ + public static final String VERBOSE_PROPNAME = "verbose"; + + /** Holds the default verbose mode. */ + public static final boolean VERBOSE_DEFAULT = false; + + /** Holds the name of the property to get the p2p or pub/sub messaging mode from. */ + public static final String PUBSUB_PROPNAME = "pubsub"; + + /** Holds the pub/sub mode default, true means ping a topic, false means ping a queue. */ + public static final boolean PUBSUB_DEFAULT = false; + + /** Holds the name of the property to get the fail after commit flag from. */ + public static final String FAIL_AFTER_COMMIT_PROPNAME = "failAfterCommit"; + + /** Holds the default failover after commit test flag. */ + public static final boolean FAIL_AFTER_COMMIT_DEFAULT = false; + + /** Holds the name of the proeprty to get the fail before commit flag from. */ + public static final String FAIL_BEFORE_COMMIT_PROPNAME = "failBeforeCommit"; + + /** Holds the default failover before commit test flag. */ + public static final boolean FAIL_BEFORE_COMMIT_DEFAULT = false; + + /** Holds the name of the proeprty to get the fail after send flag from. */ + public static final String FAIL_AFTER_SEND_PROPNAME = "failAfterSend"; + + /** Holds the default failover after send test flag. */ + public static final boolean FAIL_AFTER_SEND_DEFAULT = false; + + /** Holds the name of the property to get the fail before send flag from. */ + public static final String FAIL_BEFORE_SEND_PROPNAME = "failBeforeSend"; + + /** Holds the default failover before send test flag. */ + public static final boolean FAIL_BEFORE_SEND_DEFAULT = false; + + /** Holds the name of the property to get the fail once flag from. */ + public static final String FAIL_ONCE_PROPNAME = "failOnce"; + + /** The default failover once flag, true means only do one failover, false means failover on every commit cycle. */ + public static final boolean FAIL_ONCE_DEFAULT = true; + + /** Holds the name of the property to get the broker access username from. */ + public static final String USERNAME_PROPNAME = "username"; + + /** Holds the default broker log on username. */ + public static final String USERNAME_DEFAULT = "guest"; + + /** Holds the name of the property to get the broker access password from. */ + public static final String PASSWORD_PROPNAME = "password"; + + /** Holds the default broker log on password. */ + public static final String PASSWORD_DEFAULT = "guest"; + + /** Holds the name of the proeprty to get the. */ + public static final String SELECTOR_PROPNAME = "selector"; + + /** Holds the default message selector. */ + public static final String SELECTOR_DEFAULT = ""; + + /** Holds the name of the property to get the destination count from. */ + public static final String DESTINATION_COUNT_PROPNAME = "destinationCount"; + + /** Defines the default number of destinations to ping. */ + public static final int DESTINATION_COUNT_DEFAULT = 1; + + /** Holds the name of the property to get the number of consumers per destination from. */ + public static final String NUM_CONSUMERS_PROPNAME = "numConsumers"; + + /** Defines the default number consumers per destination. */ + public static final int NUM_CONSUMERS_DEFAULT = 1; + + /** Holds the name of the property to get the waiting timeout for response messages. */ + public static final String TIMEOUT_PROPNAME = "timeout"; + + /** Default time to wait before assuming that a ping has timed out. */ + public static final long TIMEOUT_DEFAULT = 30000; + + /** Holds the name of the property to get the commit batch size from. */ + public static final String TX_BATCH_SIZE_PROPNAME = "commitBatchSize"; + + /** Defines the default number of pings to send in each transaction when running transactionally. */ + public static final int TX_BATCH_SIZE_DEFAULT = 1; + + /** Holds the name of the property to get the unique destinations flag from. */ + public static final String UNIQUE_DESTS_PROPNAME = "uniqueDests"; + + /** Defines the default value for the unique destinations property. */ + public static final boolean UNIQUE_DESTS_DEFAULT = true; + + /** Holds the name of the property to get the durable destinations flag from. */ + public static final String DURABLE_DESTS_PROPNAME = "durableDests"; + + /** Defines the default value of the durable destinations flag. */ + public static final boolean DURABLE_DESTS_DEFAULT = false; + + /** Holds the name of the proeprty to get the message acknowledgement mode from. */ + public static final String ACK_MODE_PROPNAME = "ackMode"; + + /** Defines the default message acknowledgement mode. */ + public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; + + /** Holds the name of the property to get the consumers message acknowledgement mode from. */ + public static final String CONSUMER_ACK_MODE_PROPNAME = "consAckMode"; + + /** Defines the default consumers message acknowledgement mode. */ + public static final int CONSUMER_ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE; + + /** Holds the name of the property to get the maximum pending message size setting from. */ + public static final String MAX_PENDING_PROPNAME = "maxPending"; + + /** Defines the default value for the maximum pending message size setting. 0 means no limit. */ + public static final int MAX_PENDING_DEFAULT = 0; + + /** Defines the default prefetch size to use when consuming messages. */ + public static final int PREFETCH_DEFAULT = 100; + + /** Defines the default value of the no local flag to use when consuming messages. */ + public static final boolean NO_LOCAL_DEFAULT = false; + + /** Defines the default value of the exclusive flag to use when consuming messages. */ + public static final boolean EXCLUSIVE_DEFAULT = false; + + /** Holds the name of the property to store nanosecond timestamps in ping messages with. */ + public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp"; + + /** Holds the default configuration properties. */ + public static ParsedProperties defaults = new ParsedProperties(); + + static + { + defaults.setPropertyIfNull(OVERRIDE_CLIENT_ID_PROPNAME, OVERRIDE_CLIENT_ID_DEAFULT); + defaults.setPropertyIfNull(FILE_PROPERTIES_PROPNAME, FILE_PROPERTIES_DEAFULT); + defaults.setPropertyIfNull(FACTORY_NAME_PROPNAME, FACTORY_NAME_DEAFULT); + defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT); + defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT); + defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT); + defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT); + defaults.setPropertyIfNull(PING_QUEUE_NAME_PROPNAME, PING_QUEUE_NAME_DEFAULT); + defaults.setPropertyIfNull(QUEUE_NAME_POSTFIX_PROPNAME, QUEUE_NAME_POSTFIX_DEFAULT); + defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT); + defaults.setPropertyIfNull(TRANSACTED_PROPNAME, TRANSACTED_DEFAULT); + defaults.setPropertyIfNull(CONSUMER_TRANSACTED_PROPNAME, CONSUMER_TRANSACTED_DEFAULT); + defaults.setPropertyIfNull(PERSISTENT_MODE_PROPNAME, PERSISTENT_MODE_DEFAULT); + defaults.setPropertyIfNull(ACK_MODE_PROPNAME, ACK_MODE_DEFAULT); + defaults.setPropertyIfNull(CONSUMER_ACK_MODE_PROPNAME, CONSUMER_ACK_MODE_DEFAULT); + defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT); + defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT); + defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT); + defaults.setPropertyIfNull(UNIQUE_DESTS_PROPNAME, UNIQUE_DESTS_DEFAULT); + defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT); + defaults.setPropertyIfNull(FAIL_BEFORE_COMMIT_PROPNAME, FAIL_BEFORE_COMMIT_DEFAULT); + defaults.setPropertyIfNull(FAIL_AFTER_COMMIT_PROPNAME, FAIL_AFTER_COMMIT_DEFAULT); + defaults.setPropertyIfNull(FAIL_BEFORE_SEND_PROPNAME, FAIL_BEFORE_SEND_DEFAULT); + defaults.setPropertyIfNull(FAIL_AFTER_SEND_PROPNAME, FAIL_AFTER_SEND_DEFAULT); + defaults.setPropertyIfNull(FAIL_ONCE_PROPNAME, FAIL_ONCE_DEFAULT); + defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT); + defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT); + defaults.setPropertyIfNull(NUM_CONSUMERS_PROPNAME, NUM_CONSUMERS_DEFAULT); + defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT); + defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT); + defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT); + } + + /** Allows setting of client ID on the connection, rather than through the connection URL. */ + protected boolean _overrideClientId; + + /** Holds the JNDI name of the JMS connection factory. */ + protected String _factoryName; + + /** Holds the name of the properties file to configure JNDI with. */ + protected String _fileProperties; + + /** Holds the broker url. */ + protected String _brokerDetails; + + /** Holds the username to access the broker with. */ + protected String _username; + + /** Holds the password to access the broker with. */ + protected String _password; + + /** Holds the virtual host on the broker to run the tests through. */ + protected String _virtualpath; + + /** Holds the root name from which to generate test destination names. */ + protected String _destinationName; + + /** Holds the default queue name postfix value. */ + protected String _queueNamePostfix; + + /** Holds the message selector to filter the pings with. */ + protected String _selector; + + /** Holds the producers transactional mode flag. */ + protected boolean _transacted; + + /** Holds the consumers transactional mode flag. */ + protected boolean _consTransacted; + + /** Determines whether this producer sends persistent messages. */ + protected boolean _persistent; + + /** Holds the acknowledgement mode used for the producers. */ + protected int _ackMode; + + /** Holds the acknowledgement mode setting for the consumers. */ + protected int _consAckMode; + + /** Determines what size of messages this producer sends. */ + protected int _messageSize; + + /** Used to indicate that the ping loop should print out whenever it pings. */ + protected boolean _verbose; + + /** Flag used to indicate if this is a point to point or pub/sub ping client. */ + protected boolean _isPubSub; + + /** Flag used to indicate if the destinations should be unique client. */ + protected boolean _isUnique; + + /** Flag used to indicate that durable destination should be used. */ + protected boolean _isDurable; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a commit. */ + protected boolean _failBeforeCommit; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a commit. */ + protected boolean _failAfterCommit; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover before a send. */ + protected boolean _failBeforeSend; + + /** Flag used to indicate that the user should be prompted to terminate a broker, to test failover after a send. */ + protected boolean _failAfterSend; + + /** Flag used to indicate that failover prompting should only be done on the first commit, not on every commit. */ + protected boolean _failOnce; + + /** Holds the number of sends that should be performed in every transaction when using transactions. */ + protected int _txBatchSize; + + /** Holds the number of destinations to ping. */ + protected int _noOfDestinations; + + /** Holds the number of consumers per destination. */ + protected int _noOfConsumers; + + /** Holds the maximum send rate in herz. */ + protected int _rate; + + /** + * Holds the size of the maximum amount of pending data that the client should buffer, sending is suspended + * if this limit is breached. + */ + protected int _maxPendingSize; + + /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ + private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); + + /** A source for providing sequential unqiue ids for instances of this class to be identifed with. */ + private static AtomicInteger _instanceIdGenerator = new AtomicInteger(0); + + /** Holds this instances unique id. */ + private int instanceId; + + /** + * Holds a map from message ids to latches on which threads wait for replies. This map is shared accross multiple + * ping producers on the same JVM. + */ + private static Map perCorrelationIds = + Collections.synchronizedMap(new HashMap()); + + /** A convenient formatter to use when time stamping output. */ + protected static final DateFormat timestampFormatter = new SimpleDateFormat("hh:mm:ss:SS"); + + /** Holds the connection for the message producer. */ + protected Connection _connection; + + /** Holds the consumer connections. */ + protected Connection[] _consumerConnection; + + /** Holds the controlSession on which ping replies are received. */ + protected Session[] _consumerSession; + + /** Holds the producer controlSession, needed to create ping messages. */ + protected Session _producerSession; + + /** Holds the destination where the response messages will arrive. */ + protected Destination _replyDestination; + + /** Holds the set of destinations that this ping producer pings. */ + protected List _pingDestinations; + + /** Used to restrict the sending rate to a specified limit. */ + protected Throttle _rateLimiter; + + /** Holds a message listener that this message listener chains all its messages to. */ + protected ChainedMessageListener _chainedMessageListener = null; + + /** + * This id generator is used to generate ids to append to the queue name to ensure that queues can be unique when + * creating multiple ping producers in the same JVM. + */ + protected static AtomicInteger _queueJVMSequenceID = new AtomicInteger(); + + /** + * This id generator is used to generates ids that are only unique within this pinger. Creating multiple pingers + * on the same JVM using this id generator will allow them to ping on the same queues. + */ + protected AtomicInteger _queueSharedID = new AtomicInteger(); + + /** Used to tell the ping loop when to terminate, it only runs while this is true. */ + protected boolean _publish = true; + + /** Holds the message producer to send the pings through. */ + protected MessageProducer _producer; + + /** Holds the message consumer to receive the ping replies through. */ + protected MessageConsumer[] _consumer; + + /** The prompt to display when asking the user to kill the broker for failover testing. */ + private static final String KILL_BROKER_PROMPT = "Kill broker now, then press Return."; + + /** Holds the name for this test client to be identified to the broker with. */ + private String _clientID; + + /** Keeps count of the total messages sent purely for debugging purposes. */ + private static AtomicInteger numSent = new AtomicInteger(); + + /** + * Holds a monitor which is used to synchronize sender and receivers threads, where the sender has elected + * to wait until the number of unreceived message is reduced before continuing to send. This monitor is a + * fair SynchronousQueue becuase that provides fair scheduling, to ensure that all producer threads get an + * equal chance to produce messages. + */ + static final SynchronousQueue _sendPauseMonitor = new SynchronousQueue(true); + + /** Keeps a count of the number of message currently sent but not received. */ + static AtomicInteger _unreceived = new AtomicInteger(0); + + /** + * Creates a ping producer with the specified parameters, of which there are many. See the class level comments + * for details. This constructor creates a connection to the broker and creates producer and consumer sessions on + * it, to send and recieve its pings and replies on. + * + * @param overrides Properties containing any desired overrides to the defaults. + * + * @throws Exception Any exceptions are allowed to fall through. + */ + public PingPongProducer(Properties overrides) throws Exception + { + // log.debug("public PingPongProducer(Properties overrides = " + overrides + "): called"); + instanceId = _instanceIdGenerator.getAndIncrement(); + + // Create a set of parsed properties from the defaults overriden by the passed in values. + ParsedProperties properties = new ParsedProperties(defaults); + properties.putAll(overrides); + + // Extract the configuration properties to set the pinger up with. + _overrideClientId = properties.getPropertyAsBoolean(OVERRIDE_CLIENT_ID_PROPNAME); + _factoryName = properties.getProperty(FACTORY_NAME_PROPNAME); + _fileProperties = properties.getProperty(FILE_PROPERTIES_PROPNAME); + _brokerDetails = properties.getProperty(BROKER_PROPNAME); + _username = properties.getProperty(USERNAME_PROPNAME); + _password = properties.getProperty(PASSWORD_PROPNAME); + _virtualpath = properties.getProperty(VIRTUAL_HOST_PROPNAME); + _destinationName = properties.getProperty(PING_QUEUE_NAME_PROPNAME); + _queueNamePostfix = properties.getProperty(QUEUE_NAME_POSTFIX_PROPNAME); + _selector = properties.getProperty(SELECTOR_PROPNAME); + _transacted = properties.getPropertyAsBoolean(TRANSACTED_PROPNAME); + _consTransacted = properties.getPropertyAsBoolean(CONSUMER_TRANSACTED_PROPNAME); + _persistent = properties.getPropertyAsBoolean(PERSISTENT_MODE_PROPNAME); + _messageSize = properties.getPropertyAsInteger(MESSAGE_SIZE_PROPNAME); + _verbose = properties.getPropertyAsBoolean(VERBOSE_PROPNAME); + _failAfterCommit = properties.getPropertyAsBoolean(FAIL_AFTER_COMMIT_PROPNAME); + _failBeforeCommit = properties.getPropertyAsBoolean(FAIL_BEFORE_COMMIT_PROPNAME); + _failAfterSend = properties.getPropertyAsBoolean(FAIL_AFTER_SEND_PROPNAME); + _failBeforeSend = properties.getPropertyAsBoolean(FAIL_BEFORE_SEND_PROPNAME); + _failOnce = properties.getPropertyAsBoolean(FAIL_ONCE_PROPNAME); + _txBatchSize = properties.getPropertyAsInteger(TX_BATCH_SIZE_PROPNAME); + _noOfDestinations = properties.getPropertyAsInteger(DESTINATION_COUNT_PROPNAME); + _noOfConsumers = properties.getPropertyAsInteger(NUM_CONSUMERS_PROPNAME); + _rate = properties.getPropertyAsInteger(RATE_PROPNAME); + _isPubSub = properties.getPropertyAsBoolean(PUBSUB_PROPNAME); + _isUnique = properties.getPropertyAsBoolean(UNIQUE_DESTS_PROPNAME); + _isDurable = properties.getPropertyAsBoolean(DURABLE_DESTS_PROPNAME); + _ackMode = _transacted ? 0 : properties.getPropertyAsInteger(ACK_MODE_PROPNAME); + _consAckMode = _consTransacted ? 0 : properties.getPropertyAsInteger(CONSUMER_ACK_MODE_PROPNAME); + _maxPendingSize = properties.getPropertyAsInteger(MAX_PENDING_PROPNAME); + + // Check that one or more destinations were specified. + if (_noOfDestinations < 1) + { + throw new IllegalArgumentException("There must be at least one destination."); + } + + // Set up a throttle to control the send rate, if a rate > 0 is specified. + if (_rate > 0) + { + _rateLimiter = new BatchedThrottle(); + _rateLimiter.setRate(_rate); + } + + // Create the connection and message producers/consumers. + // establishConnection(true, true); + } + + /** + * Establishes a connection to the broker and creates message consumers and producers based on the parameters + * that this ping client was created with. + * + * @param producer Flag to indicate whether or not the producer should be set up. + * @param consumer Flag to indicate whether or not the consumers should be set up. + * + * @throws Exception Any exceptions are allowed to fall through. + */ + public void establishConnection(boolean producer, boolean consumer) throws Exception + { + // log.debug("public void establishConnection(): called"); + + // Generate a unique identifying name for this client, based on it ip address and the current time. + InetAddress address = InetAddress.getLocalHost(); + // _clientID = address.getHostName() + System.currentTimeMillis(); + _clientID = "perftest_" + instanceId; + + // Create a connection to the broker. + createConnection(_clientID); + + // Create transactional or non-transactional sessions, based on the command line arguments. + _producerSession = _connection.createSession(_transacted, _ackMode); + + _consumerSession = new Session[_noOfConsumers]; + + for (int i = 0; i < _noOfConsumers; i++) + { + _consumerSession[i] = _consumerConnection[i].createSession(_consTransacted, _consAckMode); + } + + // Create the destinations to send pings to and receive replies from. + _replyDestination = _consumerSession[0].createTemporaryQueue(); + createPingDestinations(_noOfDestinations, _selector, _destinationName, _isUnique, _isDurable); + + // Create the message producer only if instructed to. + if (producer) + { + createProducer(); + } + + // Create the message consumer only if instructed to. + if (consumer) + { + createReplyConsumers(getReplyDestinations(), _selector); + } + } + + /** + * Establishes a connection to the broker, based on the configuration parameters that this ping client was + * created with. + * + * @param clientID The clients identifier. + * + * @throws JMSException Underlying exceptions allowed to fall through. + * @throws NamingException Underlying exceptions allowed to fall through. + * @throws IOException Underlying exceptions allowed to fall through. + */ + protected void createConnection(String clientID) throws JMSException, NamingException, IOException + { + // _log.debug("protected void createConnection(String clientID = " + clientID + "): called"); + + // _log.debug("Creating a connection for the message producer."); + File propsFile = new File(_fileProperties); + InputStream is = new FileInputStream(propsFile); + Properties properties = new Properties(); + properties.load(is); + + Context context = new InitialContext(properties); + ConnectionFactory factory = (ConnectionFactory) context.lookup(_factoryName); + _connection = factory.createConnection(_username, _password); + + if (_overrideClientId) + { + _connection.setClientID(clientID); + } + + // _log.debug("Creating " + _noOfConsumers + " connections for the consumers."); + + _consumerConnection = new Connection[_noOfConsumers]; + + for (int i = 0; i < _noOfConsumers; i++) + { + _consumerConnection[i] = factory.createConnection(_username, _password); + // _consumerConnection[i].setClientID(clientID); + } + } + + /** + * Starts a ping-pong loop running from the command line. The bounce back client {@link PingPongBouncer} also needs + * to be started to bounce the pings back again. + * + * @param args The command line arguments. + */ + public static void main(String[] args) + { + try + { + Properties options = + CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); + + // Create a ping producer overriding its defaults with all options passed on the command line. + PingPongProducer pingProducer = new PingPongProducer(options); + pingProducer.establishConnection(true, true); + + // Start the ping producers dispatch thread running. + pingProducer._connection.start(); + + // Create a shutdown hook to terminate the ping-pong producer. + Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook()); + + // Ensure that the ping pong producer is registered to listen for exceptions on the connection too. + pingProducer._connection.setExceptionListener(pingProducer); + + // Create the ping loop thread and run it until it is terminated by the shutdown hook or exception. + Thread pingThread = new Thread(pingProducer); + pingThread.run(); + pingThread.join(); + } + catch (Exception e) + { + System.err.println(e.getMessage()); + log.error("Top level handler caught execption.", e); + System.exit(1); + } + } + + /** + * Convenience method for a short pause. + * + * @param sleepTime The time in milliseconds to pause for. + */ + public static void pause(long sleepTime) + { + if (sleepTime > 0) + { + try + { + Thread.sleep(sleepTime); + } + catch (InterruptedException ie) + { } + } + } + + /** + * Gets all the reply destinations (to listen for replies on). In this case this will just be the single reply to + * destination of this pinger. + * + * @return The single reply to destination of this pinger, wrapped in a list. + */ + public List getReplyDestinations() + { + // log.debug("public List getReplyDestinations(): called"); + + List replyDestinations = new ArrayList(); + replyDestinations.add(_replyDestination); + + // log.debug("replyDestinations = " + replyDestinations); + + return replyDestinations; + } + + /** + * Creates the producer to send the pings on. This is created without a default destination. Its persistent delivery + * flag is set accoring the ping producer creation options. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + public void createProducer() throws JMSException + { + // log.debug("public void createProducer(): called"); + + _producer = (MessageProducer) _producerSession.createProducer(null); + _producer.setDeliveryMode(_persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + // log.debug("Created producer for " + (_persistent ? "persistent" : "non-persistent") + " messages."); + } + + /** + * Creates consumers for the specified number of destinations. The destinations themselves are also created by this + * method. + * + * @param noOfDestinations The number of destinations to create consumers for. + * @param selector The message selector to filter the consumers with. + * @param rootName The root of the name, or actual name if only one is being created. + * @param unique true to make the destinations unique to this pinger, false to share the + * numbering with all pingers on the same JVM. + * @param durable If the destinations are durable topics. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + public void createPingDestinations(int noOfDestinations, String selector, String rootName, boolean unique, + boolean durable) throws JMSException + { + /*log.debug("public void createPingDestinations(int noOfDestinations = " + noOfDestinations + ", String selector = " + + selector + ", String rootName = " + rootName + ", boolean unique = " + unique + ", boolean durable = " + + durable + "): called");*/ + + _pingDestinations = new ArrayList(); + + // Create the desired number of ping destinations and consumers for them. + // log.debug("Creating " + noOfDestinations + " destinations to ping."); + + for (int i = 0; i < noOfDestinations; i++) + { + Destination destination; + String id; + + // Generate an id, unique within this pinger or to the whole JVM depending on the unique flag. + if (unique) + { + // log.debug("Creating unique destinations."); + id = "_" + _queueJVMSequenceID.incrementAndGet() + "_" + _connection.getClientID(); + } + else + { + // log.debug("Creating shared destinations."); + id = "_" + _queueSharedID.incrementAndGet(); + } + + // Check if this is a pub/sub pinger, in which case create topics. + if (_isPubSub) + { + destination = _producerSession.createTopic(rootName + id); + // log.debug("Created non-durable topic " + destination); + + if (durable) + { + _producerSession.createDurableSubscriber((Topic) destination, _connection.getClientID()); + } + } + // Otherwise this is a p2p pinger, in which case create queues. + else + { + destination = _producerSession.createQueue(rootName + id + _queueNamePostfix); + // log.debug("Created queue " + destination); + } + + // Keep the destination. + _pingDestinations.add(destination); + } + } + + /** + * Creates consumers for the specified destinations and registers this pinger to listen to their messages. + * + * @param destinations The destinations to listen to. + * @param selector A selector to filter the messages with. + * + * @throws javax.jms.JMSException Any JMSExceptions are allowed to fall through. + */ + public void createReplyConsumers(Collection destinations, String selector) throws JMSException + { + /*log.debug("public void createReplyConsumers(Collection destinations = " + destinations + + ", String selector = " + selector + "): called");*/ + + log.debug("There are " + destinations.size() + " destinations."); + log.debug("Creating " + _noOfConsumers + " consumers on each destination."); + log.debug("Total number of consumers is: " + (destinations.size() * _noOfConsumers)); + + for (Destination destination : destinations) + { + _consumer = new MessageConsumer[_noOfConsumers]; + + for (int i = 0; i < _noOfConsumers; i++) + { + // Create a consumer for the destination and set this pinger to listen to its messages. + _consumer[i] = _consumerSession[i].createConsumer(destination, selector, NO_LOCAL_DEFAULT); + + final int consumerNo = i; + + _consumer[i].setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + onMessageWithConsumerNo(message, consumerNo); + } + }); + + log.debug("Set consumer " + i + " to listen to replies sent to destination: " + destination); + } + } + } + + /** + * Stores the received message in the replies map, then resets the boolean latch that a thread waiting for a + * correlating reply may be waiting on. This is only done if the reply has a correlation id that is expected in the + * replies map. + * + * @param message The received message. + * @param consumerNo The consumer number within this test pinger instance. + */ + public void onMessageWithConsumerNo(Message message, int consumerNo) + { + // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo = " + consumerNo + "): called"); + try + { + long now = System.nanoTime(); + long timestamp = getTimestamp(message); + long pingTime = now - timestamp; + + // NDC.push("id" + instanceId + "/cons" + consumerNo); + + // Extract the messages correlation id. + String correlationID = message.getJMSCorrelationID(); + // log.debug("correlationID = " + correlationID); + + // int num = message.getIntProperty("MSG_NUM"); + // log.info("Message " + num + " received."); + + boolean isRedelivered = message.getJMSRedelivered(); + // log.debug("isRedelivered = " + isRedelivered); + + if (!isRedelivered) + { + // Countdown on the traffic light if there is one for the matching correlation id. + PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); + + if (perCorrelationId != null) + { + CountDownLatch trafficLight = perCorrelationId.trafficLight; + + // Restart the timeout timer on every message. + perCorrelationId.timeOutStart = System.nanoTime(); + + // log.debug("Reply was expected, decrementing the latch for the id, " + correlationID); + + // Release waiting senders if there are some and using maxPending limit. + if ((_maxPendingSize > 0)) + { + // Decrement the count of sent but not yet received messages. + int unreceived = _unreceived.decrementAndGet(); + int unreceivedSize = + (unreceived * ((_messageSize == 0) ? 1 : _messageSize)) + / (_isPubSub ? getConsumersPerDestination() : 1); + + // log.debug("unreceived = " + unreceived); + // log.debug("unreceivedSize = " + unreceivedSize); + + // synchronized (_sendPauseMonitor) + // { + if (unreceivedSize < _maxPendingSize) + { + _sendPauseMonitor.poll(); + } + // } + } + + // Decrement the countdown latch. Before this point, it is possible that two threads might enter this + // method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block + // ensures that each thread will get a unique value for the remaining messages. + long trueCount; + long remainingCount; + + synchronized (trafficLight) + { + trafficLight.countDown(); + + trueCount = trafficLight.getCount(); + remainingCount = trueCount - 1; + + // NDC.push("/rem" + remainingCount); + + // log.debug("remainingCount = " + remainingCount); + // log.debug("trueCount = " + trueCount); + + // Commit on transaction batch size boundaries. At this point in time the waiting producer + // remains blocked, even on the last message. + // Commit count is divided by noOfConsumers in p2p mode, so that each consumer only commits on + // each batch boundary. For pub/sub each consumer gets every message so no division is done. + // When running in client ack mode, an ack is done instead of a commit, on the commit batch + // size boundaries. + long commitCount = _isPubSub ? remainingCount : (remainingCount / _noOfConsumers); + // log.debug("commitCount = " + commitCount); + + if ((commitCount % _txBatchSize) == 0) + { + if (_consAckMode == 2) + { + // log.debug("Doing client ack for consumer " + consumerNo + "."); + message.acknowledge(); + } + else + { + // log.debug("Trying commit for consumer " + consumerNo + "."); + commitTx(_consumerSession[consumerNo]); + // log.info("Tx committed on consumer " + consumerNo); + } + } + + // Forward the message and remaining count to any interested chained message listener. + if (_chainedMessageListener != null) + { + _chainedMessageListener.onMessage(message, (int) remainingCount, pingTime); + } + + // Check if this is the last message, in which case release any waiting producers. This is done + // after the transaction has been committed and any listeners notified. + if (trueCount == 1) + { + trafficLight.countDown(); + } + } + } + else + { + log.warn("Got unexpected message with correlationId: " + correlationID); + } + } + else + { + log.warn("Got redelivered message, ignoring."); + } + } + catch (JMSException e) + { + log.warn("There was a JMSException: " + e.getMessage(), e); + } + finally + { + // log.debug("public void onMessageWithConsumerNo(Message message, int consumerNo): ending"); + // NDC.clear(); + } + } + + /** + * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out + * before a reply arrives, then a null reply is returned from this method. This method allows the caller to specify + * the correlation id. + * + * @param message The message to send. If this is null, one is generated. + * @param numPings The number of ping messages to send. + * @param timeout The timeout in milliseconds. + * @param messageCorrelationId The message correlation id. If this is null, one is generated. + * + * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait + * for all prematurely. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + * @throws InterruptedException When interrupted by a timeout + */ + public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) + throws JMSException, InterruptedException + { + /*log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ + + // Generate a unique correlation id to put on the messages before sending them, if one was not specified. + if (messageCorrelationId == null) + { + messageCorrelationId = Long.toString(_correlationIdGenerator.incrementAndGet()); + } + + try + { + // NDC.push("prod"); + + // Create a count down latch to count the number of replies with. This is created before the messages are + // sent so that the replies cannot be received before the count down is created. + // One is added to this, so that the last reply becomes a special case. The special case is that the + // chained message listener must be called before this sender can be unblocked, but that decrementing the + // countdown needs to be done before the chained listener can be called. + PerCorrelationId perCorrelationId = new PerCorrelationId(); + + perCorrelationId.trafficLight = new CountDownLatch(getExpectedNumPings(numPings) + 1); + perCorrelationIds.put(messageCorrelationId, perCorrelationId); + + // Set up the current time as the start time for pinging on the correlation id. This is used to determine + // timeouts. + perCorrelationId.timeOutStart = System.nanoTime(); + + // Send the specifed number of messages. + pingNoWaitForReply(message, numPings, messageCorrelationId); + + boolean timedOut; + boolean allMessagesReceived; + int numReplies; + + do + { + // Block the current thread until replies to all the messages are received, or it times out. + perCorrelationId.trafficLight.await(timeout, TimeUnit.MILLISECONDS); + + // Work out how many replies were receieved. + numReplies = getExpectedNumPings(numPings) - (int) perCorrelationId.trafficLight.getCount(); + + allMessagesReceived = numReplies == getExpectedNumPings(numPings); + + // log.debug("numReplies = " + numReplies); + // log.debug("allMessagesReceived = " + allMessagesReceived); + + // Recheck the timeout condition. + long now = System.nanoTime(); + long lastMessageReceievedAt = perCorrelationId.timeOutStart; + timedOut = (now - lastMessageReceievedAt) > (timeout * 1000000); + + // log.debug("now = " + now); + // log.debug("lastMessageReceievedAt = " + lastMessageReceievedAt); + } + while (!timedOut && !allMessagesReceived); + + if ((numReplies < getExpectedNumPings(numPings)) && _verbose) + { + log.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); + } + else if (_verbose) + { + log.info("Got all replies on id, " + messageCorrelationId); + } + + // commitTx(_consumerSession); + + // log.debug("public int pingAndWaitForReply(Message message, int numPings, long timeout): ending"); + + return numReplies; + } + // Ensure that the message countdown latch is always removed from the reply map. The reply map is long lived, + // so will be a memory leak if this is not done. + finally + { + // NDC.pop(); + perCorrelationIds.remove(messageCorrelationId); + } + } + + /** + * Sends the specified number of ping messages and does not wait for correlating replies. + * + * @param message The message to send. + * @param numPings The number of pings to send. + * @param messageCorrelationId A correlation id to place on all messages sent. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + */ + public void pingNoWaitForReply(Message message, int numPings, String messageCorrelationId) throws JMSException + { + /*log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings + + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ + + if (message == null) + { + message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent); + } + + message.setJMSCorrelationID(messageCorrelationId); + + // Set up a committed flag to detect uncommitted messages at the end of the send loop. This may occurr if the + // transaction batch size is not a factor of the number of pings. In which case an extra commit at the end is + // needed. + boolean committed = false; + + // Send all of the ping messages. + for (int i = 0; i < numPings; i++) + { + // Re-timestamp the message. + // message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); + + // Send the message, passing in the message count. + committed = sendMessage(i, message); + + // Spew out per message timings on every message sonly in verbose mode. + /*if (_verbose) + { + log.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId); + }*/ + } + + // Call commit if the send loop finished before reaching a batch size boundary so there may still be uncommitted messages. + if (!committed) + { + commitTx(_producerSession); + } + } + + /** + * Sends the sepcified message, applies rate limiting and possibly commits the current transaction. The count of + * messages sent so far must be specified and is used to round robin the ping destinations (where there are more + * than one), and to determine if the transaction batch size has been reached and the sent messages should be + * committed. + * + * @param i The count of messages sent so far in a loop of multiple calls to this send method. + * @param message The message to send. + * + * @return true if the messages were committed, false otherwise. + * + * @throws JMSException All underlyiung JMSExceptions are allowed to fall through. + */ + protected boolean sendMessage(int i, Message message) throws JMSException + { + try + { + NDC.push("id" + instanceId + "/prod"); + + // log.debug("protected boolean sendMessage(int i = " + i + ", Message message): called"); + // log.debug("_txBatchSize = " + _txBatchSize); + + // Round robin the destinations as the messages are sent. + Destination destination = _pingDestinations.get(i % _pingDestinations.size()); + + // Prompt the user to kill the broker when doing failover testing. + _failBeforeSend = waitForUserToPromptOnFailure(_failBeforeSend); + + // Get the test setup for the correlation id. + String correlationID = message.getJMSCorrelationID(); + PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID); + + // If necessary, wait until the max pending message size comes within its limit. + if (_maxPendingSize > 0) + { + synchronized (_sendPauseMonitor) + { + // Used to keep track of the number of times that send has to wait. + int numWaits = 0; + + // The maximum number of waits before the test gives up and fails. This has been chosen to correspond with + // the test timeout. + int waitLimit = (int) (TIMEOUT_DEFAULT / 10000); + + while (true) + { + // Get the size estimate of sent but not yet received messages. + int unreceived = _unreceived.get(); + int unreceivedSize = + (unreceived * ((_messageSize == 0) ? 1 : _messageSize)) + / (_isPubSub ? getConsumersPerDestination() : 1); + + // log.debug("unreceived = " + unreceived); + // log.debug("unreceivedSize = " + unreceivedSize); + // log.debug("_maxPendingSize = " + _maxPendingSize); + + if (unreceivedSize > _maxPendingSize) + { + // log.debug("unreceived size estimate over limit = " + unreceivedSize); + + // Fail the test if the send has had to wait more than the maximum allowed number of times. + if (numWaits > waitLimit) + { + String errorMessage = + "Send has had to wait for the unreceivedSize (" + unreceivedSize + + ") to come below the maxPendingSize (" + _maxPendingSize + ") more that " + waitLimit + + " times."; + log.warn(errorMessage); + throw new RuntimeException(errorMessage); + } + + // Wait on the send pause barrier for the limit to be re-established. + try + { + long start = System.nanoTime(); + // _sendPauseMonitor.wait(10000); + _sendPauseMonitor.offer(new Object(), 10000, TimeUnit.MILLISECONDS); + long end = System.nanoTime(); + + // Count the wait only if it was for > 99% of the requested wait time. + if (((float) (end - start) / (float) (10000 * 1000000L)) > 0.99) + { + numWaits++; + } + } + catch (InterruptedException e) + { + // Restore the interrupted status + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + } + else + { + break; + } + } + } + } + + // Send the message either to its round robin destination, or its default destination. + // int num = numSent.incrementAndGet(); + // message.setIntProperty("MSG_NUM", num); + setTimestamp(message); + + if (destination == null) + { + _producer.send(message); + } + else + { + _producer.send(destination, message); + } + + // Increase the unreceived size, this may actually happen after the message is received. + // The unreceived size is incremented by the number of consumers that will get a copy of the message, + // in pub/sub mode. + if (_maxPendingSize > 0) + { + int newUnreceivedCount = _unreceived.addAndGet(_isPubSub ? getConsumersPerDestination() : 1); + // log.debug("newUnreceivedCount = " + newUnreceivedCount); + } + + // Apply message rate throttling if a rate limit has been set up. + if (_rateLimiter != null) + { + _rateLimiter.throttle(); + } + + // Call commit every time the commit batch size is reached. + boolean committed = false; + + // Commit on every transaction batch size boundary. Here i + 1 is the count of actual messages sent. + if (((i + 1) % _txBatchSize) == 0) + { + // log.debug("Trying commit on producer session."); + committed = commitTx(_producerSession); + } + + return committed; + } + finally + { + NDC.clear(); + } + } + + /** + * If the specified fail flag is set, this method waits for the user to cause a failure and then indicate to the + * test that the failure has occurred, before the method returns. + * + * @param failFlag The fail flag to test. + * + * @return The new value for the fail flag. If the {@link #_failOnce} flag is set, then each fail flag is only + * used once, then reset. + */ + private boolean waitForUserToPromptOnFailure(boolean failFlag) + { + if (failFlag) + { + if (_failOnce) + { + failFlag = false; + } + + // log.debug("Failing Before Send"); + waitForUser(KILL_BROKER_PROMPT); + } + + return failFlag; + } + + /** + * Implements a single iteration of the ping loop. This sends the number of pings specified by the transaction batch + * size property, and waits for replies to all of them. Any errors cause the publish flag to be cleared, which will + * terminate the pinger. + */ + public void pingLoop() + { + try + { + // Generate a sample message and time stamp it. + Message msg = getTestMessage(_replyDestination, _messageSize, _persistent); + // setTimestamp(msg); + + // Send the message and wait for a reply. + pingAndWaitForReply(msg, TX_BATCH_SIZE_DEFAULT, TIMEOUT_DEFAULT, null); + } + catch (JMSException e) + { + _publish = false; + // log.debug("There was a JMSException: " + e.getMessage(), e); + } + catch (InterruptedException e) + { + _publish = false; + // log.debug("There was an interruption: " + e.getMessage(), e); + } + } + + /** + * Sets a chained message listener. The message listener on this pinger, chains all its messages to the one set + * here. + * + * @param messageListener The chained message listener. + */ + public void setChainedMessageListener(ChainedMessageListener messageListener) + { + _chainedMessageListener = messageListener; + } + + /** Removes any chained message listeners from this pinger. */ + public void removeChainedMessageListener() + { + _chainedMessageListener = null; + } + + /** + * Generates a test message of the specified size, with the specified reply-to destination and persistence flag. + * + * @param replyQueue The reply-to destination for the message. + * @param messageSize The desired size of the message in bytes. + * @param persistent true if the message should use persistent delivery, false otherwise. + * + * @return A freshly generated test message. + * + * @throws javax.jms.JMSException All underlying JMSException are allowed to fall through. + */ + public Message getTestMessage(Destination replyQueue, int messageSize, boolean persistent) throws JMSException + { + // return TestMessageFactory.newObjectMessage(_producerSession, replyQueue, messageSize, persistent); + return TestUtils.createTestMessageOfSize(_producerSession, messageSize); + } + + /** + * Sets the current time in nanoseconds as the timestamp on the message. + * + * @param msg The message to timestamp. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + protected void setTimestamp(Message msg) throws JMSException + { + /*if (((AMQSession)_producerSession).isStrictAMQP()) + { + ((AMQMessage)msg).setTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME), System.nanoTime()); + } + else + {*/ + msg.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime()); + // } + } + + /** + * Extracts the nanosecond timestamp from a message. + * + * @param msg The message to extract the time stamp from. + * + * @return The timestamp in nanos. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + protected long getTimestamp(Message msg) throws JMSException + { + /*if (((AMQSession)_producerSession).isStrictAMQP()) + { + Long value = ((AMQMessage)msg).getTimestampProperty(new AMQShortString(MESSAGE_TIMESTAMP_PROPNAME)); + + return (value == null) ? 0L : value; + } + else + {*/ + return msg.getLongProperty(PingPongProducer.MESSAGE_TIMESTAMP_PROPNAME); + // } + } + + /** + * Stops the ping loop by clearing the publish flag. The current loop will complete when it notices that this flag + * has been cleared. + */ + public void stop() + { + _publish = false; + } + + /** + * Starts the producer and consumer connections. + * + * @throws JMSException Any JMSExceptions are allowed to fall through. + */ + public void start() throws JMSException + { + // log.debug("public void start(): called"); + + _connection.start(); + // log.debug("Producer started."); + + for (int i = 0; i < _noOfConsumers; i++) + { + _consumerConnection[i].start(); + // log.debug("Consumer " + i + " started."); + } + } + + /** Implements a ping loop that repeatedly pings until the publish flag becomes false. */ + public void run() + { + // Keep running until the publish flag is cleared. + while (_publish) + { + pingLoop(); + } + } + + /** + * Callback method, implementing ExceptionListener. This should be registered to listen for exceptions on the + * connection, this clears the publish flag which in turn will halt the ping loop. + * + * @param e The exception that triggered this callback method. + */ + public void onException(JMSException e) + { + // log.debug("public void onException(JMSException e = " + e + "): called", e); + _publish = false; + } + + /** + * Gets a shutdown hook that will cleanly shut this down when it is running the ping loop. This can be registered + * with the runtime system as a shutdown hook. + * + * @return A shutdown hook for the ping loop. + */ + public Thread getShutdownHook() + { + return new Thread(new Runnable() + { + public void run() + { + stop(); + } + }); + } + + /** + * Closes all of the producer and consumer connections. + * + * @throws JMSException All JMSException are allowed to fall through. + */ + public void close() throws JMSException + { + // log.debug("public void close(): called"); + + try + { + if (_connection != null) + { + // log.debug("Before close producer connection."); + _connection.close(); + // log.debug("Closed producer connection."); + } + + for (int i = 0; i < _noOfConsumers; i++) + { + if (_consumerConnection[i] != null) + { + // log.debug("Before close consumer connection " + i + "."); + _consumerConnection[i].close(); + // log.debug("Closed consumer connection " + i + "."); + } + } + } + finally + { + _connection = null; + _producerSession = null; + _consumerSession = null; + _consumerConnection = null; + _producer = null; + _consumer = null; + _pingDestinations = null; + _replyDestination = null; + } + } + + /** + * Convenience method to commit the transaction on the specified controlSession. If the controlSession to commit on is not a + * transactional controlSession, this method does nothing (unless the failover after send flag is set). + * + *

    If the {@link #_failAfterSend} flag is set, this will prompt the user to kill the broker before the commit is + * applied. This flag applies whether the pinger is transactional or not. + * + *

    If the {@link #_failBeforeCommit} flag is set, this will prompt the user to kill the broker before the commit + * is applied. If the {@link #_failAfterCommit} flag is set, this will prompt the user to kill the broker after the + * commit is applied. These flags will only apply if using a transactional pinger. + * + * @param session The controlSession to commit + * + * @return true if the controlSession was committed, false if it was not. + * + * @throws javax.jms.JMSException If the commit fails and then the rollback fails. + * + * @todo Consider moving the fail after send logic into the send method. It is confusing to have it in this commit + * method, because commits only apply to transactional pingers, but fail after send applied to transactional and + * non-transactional alike. + */ + protected boolean commitTx(Session session) throws JMSException + { + // log.debug("protected void commitTx(Session session): called"); + + boolean committed = false; + + _failAfterSend = waitForUserToPromptOnFailure(_failAfterSend); + + if (session.getTransacted()) + { + // log.debug("Session is transacted."); + + try + { + _failBeforeCommit = waitForUserToPromptOnFailure(_failBeforeCommit); + + long start = System.nanoTime(); + session.commit(); + committed = true; + // log.debug("Time taken to commit :" + ((System.nanoTime() - start) / 1000000f) + " ms"); + + _failAfterCommit = waitForUserToPromptOnFailure(_failAfterCommit); + + // log.debug("Session Commited."); + } + catch (JMSException e) + { + // log.debug("JMSException on commit:" + e.getMessage(), e); + + try + { + session.rollback(); + // log.debug("Message rolled back."); + } + catch (JMSException jmse) + { + // log.debug("JMSE on rollback:" + jmse.getMessage(), jmse); + + // Both commit and rollback failed. Throw the rollback exception. + throw jmse; + } + } + } + + return committed; + } + + /** + * Outputs a prompt to the console and waits for the user to press return. + * + * @param prompt The prompt to display on the console. + */ + public void waitForUser(String prompt) + { + System.out.println(prompt); + + try + { + System.in.read(); + } + catch (IOException e) + { + // Ignored. + } + + System.out.println("Continuing."); + } + + /** + * Gets the number of consumers that are listening to each destination in the test. + * + * @return int The number of consumers subscribing to each topic. + */ + public int getConsumersPerDestination() + { + return _noOfConsumers; + } + + /** + * Calculates how many pings are expected to be received for the given number sent. + * + * @param numpings The number of pings that will be sent. + * + * @return The number that should be received, for the test to pass. + */ + public int getExpectedNumPings(int numpings) + { + // log.debug("public int getExpectedNumPings(int numpings = " + numpings + "): called"); + + // log.debug("Each ping will be received by " + (_isPubSub ? getConsumersPerDestination() : 1) + " consumers."); + + return numpings * (_isPubSub ? getConsumersPerDestination() : 1); + } + + /** + * Defines a chained message listener interface that can be attached to this pinger. Whenever this pinger's {@link + * PingPongProducer#onMessageWithConsumerNo} method is called, the chained listener set through the {@link + * PingPongProducer#setChainedMessageListener} method is passed the message, and the remaining expected count of + * messages with that correlation id. + * + *

    Provided only one pinger is producing messages with that correlation id, the chained listener will always be + * given unique message counts. It will always be called while the producer waiting for all messages to arrive is + * still blocked. + */ + public static interface ChainedMessageListener + { + /** + * Notifies interested listeners about message arrival and important test stats, the number of messages + * remaining in the test, and the messages send timestamp. + * + * @param message The newly arrived message. + * @param remainingCount The number of messages left to complete the test. + * @param latency The nanosecond latency of the message. + * + * @throws JMSException Any JMS exceptions is allowed to fall through. + */ + public void onMessage(Message message, int remainingCount, long latency) throws JMSException; + } + + /** + * Holds information on each correlation id. The countdown latch, the current timeout timer... More stuff to be + * added to this: read/write lock to make onMessage more concurrent as described in class header comment. + */ + protected static class PerCorrelationId + { + /** Holds a countdown on number of expected messages. */ + CountDownLatch trafficLight; + + /** Holds the last timestamp that the timeout was reset to. */ + Long timeOutStart; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java index 2610b32220..009254c612 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongTestPerf.java @@ -1,251 +1,251 @@ -/* - * - * 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.qpid.requestreply; - -import junit.framework.Assert; -import junit.framework.Test; -import junit.framework.TestSuite; - -import org.apache.log4j.Logger; - -import org.apache.qpid.junit.extensions.AsymptoticTestCase; -import org.apache.qpid.junit.extensions.util.ParsedProperties; -import org.apache.qpid.junit.extensions.util.TestContextProperties; - -import javax.jms.*; - -/** - * PingPongTestPerf is a full round trip ping test, that has been written with the intention of being scaled up to run - * many times simultaneously to simluate many clients/producer/connections. A full round trip ping sends a message from - * a producer to a conumer, then the consumer replies to the message on a temporary queue. - * - *

    A single run of the test using the default JUnit test runner will result in the sending and timing of the number - * of pings specified by the test size and time how long it takes for all of these to complete. This test may be scaled - * up using a suitable JUnit test runner. See {@link org.apache.qpid.junit.extensions.TKTestRunner} for more - * information on how to do this. - * - *

    The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a - * temporary queue for replies. This setup is only established once for all the test repeats, but each test threads - * gets its own connection/producer/consumer, this is only re-established if the connection is lost. - * - *

    The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that - * is the name of the temporary queue, fires off many messages on the original queue and waits for them all to come - * back on the temporary queue. - * - *

    Configurable test properties: message size, transacted or not, persistent or not. Broker connection details. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    - */ -public class PingPongTestPerf extends AsymptoticTestCase -{ - private static Logger _logger = Logger.getLogger(PingPongTestPerf.class); - - /** Thread local to hold the per-thread test setup fields. */ - ThreadLocal threadSetup = new ThreadLocal(); - - // Set up a property reader to extract the test parameters from. Once ContextualProperties is available in - // the project dependencies, use it to get property overrides for configurable tests and to notify the test runner - // of the test parameters to log with the results. It also providers some basic type parsing convenience methods. - // private Properties testParameters = System.getProperties(); - private ParsedProperties testParameters = - TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/); - - public PingPongTestPerf(String name) - { - super(name); - - _logger.debug(testParameters); - - // Sets up the test parameters with defaults. - /*testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME, - Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.MESSAGE_SIZE_PROPNAME, - Integer.toString(PingPongProducer.MESSAGE_SIZE_DEAFULT)); - testParameters.setPropertyIfNull(PingPongProducer.PING_QUEUE_NAME_PROPNAME, - PingPongProducer.PING_QUEUE_NAME_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.PERSISTENT_MODE_PROPNAME, - Boolean.toString(PingPongProducer.PERSISTENT_MODE_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.TRANSACTED_PROPNAME, - Boolean.toString(PingPongProducer.TRANSACTED_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.BROKER_PROPNAME, PingPongProducer.BROKER_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.USERNAME_PROPNAME, PingPongProducer.USERNAME_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.PASSWORD_PROPNAME, PingPongProducer.PASSWORD_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.VIRTUAL_HOST_PROPNAME, PingPongProducer.VIRTUAL_HOST_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.VERBOSE_PROPNAME, - Boolean.toString(PingPongProducer.VERBOSE_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.RATE_PROPNAME, Integer.toString(PingPongProducer.RATE_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.PUBSUB_PROPNAME, - Boolean.toString(PingPongProducer.PUBSUB_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME, - Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.TIMEOUT_PROPNAME, Long.toString(PingPongProducer.TIMEOUT_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.DESTINATION_COUNT_PROPNAME, - Integer.toString(PingPongProducer.DESTINATION_COUNT_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_COMMIT_PROPNAME, - PingPongProducer.FAIL_AFTER_COMMIT_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_COMMIT_PROPNAME, - PingPongProducer.FAIL_BEFORE_COMMIT_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_SEND_PROPNAME, - PingPongProducer.FAIL_AFTER_SEND_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_SEND_PROPNAME, - PingPongProducer.FAIL_BEFORE_SEND_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.FAIL_ONCE_PROPNAME, PingPongProducer.FAIL_ONCE_DEFAULT); - testParameters.setPropertyIfNull(PingPongProducer.UNIQUE_DESTS_PROPNAME, - Boolean.toString(PingPongProducer.UNIQUE_DESTS_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.ACK_MODE_PROPNAME, - Integer.toString(PingPongProducer.ACK_MODE_DEFAULT)); - testParameters.setPropertyIfNull(PingPongProducer.PAUSE_AFTER_BATCH_PROPNAME, - PingPongProducer.PAUSE_AFTER_BATCH_DEFAULT);*/ - } - - /** - * Compile all the tests into a test suite. - */ - public static Test suite() - { - // Build a new test suite - TestSuite suite = new TestSuite("Ping-Pong Performance Tests"); - - // Run performance tests in read committed mode. - suite.addTest(new PingPongTestPerf("testPingPongOk")); - - return suite; - } - - private static void setSystemPropertyIfNull(String propName, String propValue) - { - if (System.getProperty(propName) == null) - { - System.setProperty(propName, propValue); - } - } - - public void testPingPongOk(int numPings) throws Exception - { - // Get the per thread test setup to run the test through. - PerThreadSetup perThreadSetup = threadSetup.get(); - - // Generate a sample message. This message is already time stamped and has its reply-to destination set. - Message msg = - perThreadSetup._testPingProducer.getTestMessage(perThreadSetup._testPingProducer.getReplyDestinations().get(0), - testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), - testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); - - // Send the message and wait for a reply. - int numReplies = - perThreadSetup._testPingProducer.pingAndWaitForReply(msg, numPings, PingPongProducer.TIMEOUT_DEFAULT, null); - - // Fail the test if the timeout was exceeded. - if (numReplies != numPings) - { - Assert.fail("The ping timed out, got " + numReplies + " out of " + numPings); - } - } - - /** - * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. - */ - public void threadSetUp() - { - try - { - PerThreadSetup perThreadSetup = new PerThreadSetup(); - - // Extract the test set up paramaeters. - String brokerDetails = testParameters.getProperty(PingPongProducer.BROKER_PROPNAME); - String username = testParameters.getProperty(PingPongProducer.USERNAME_PROPNAME); - String password = testParameters.getProperty(PingPongProducer.PASSWORD_PROPNAME); - String virtualPath = testParameters.getProperty(PingPongProducer.VIRTUAL_HOST_PROPNAME); - String destinationName = testParameters.getProperty(PingPongProducer.PING_QUEUE_NAME_PROPNAME); - boolean persistent = testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME); - boolean transacted = testParameters.getPropertyAsBoolean(PingPongProducer.TRANSACTED_PROPNAME); - String selector = testParameters.getProperty(PingPongProducer.SELECTOR_PROPNAME); - boolean verbose = testParameters.getPropertyAsBoolean(PingPongProducer.VERBOSE_PROPNAME); - boolean pubsub = testParameters.getPropertyAsBoolean(PingPongProducer.PUBSUB_PROPNAME); - - synchronized (this) - { - // Establish a bounce back client on the ping queue to bounce back the pings. - perThreadSetup._testPingBouncer = - new PingPongBouncer(brokerDetails, username, password, virtualPath, destinationName, persistent, - transacted, selector, verbose, pubsub); - - // Start the connections for client and producer running. - perThreadSetup._testPingBouncer.getConnection().start(); - - // Establish a ping-pong client on the ping queue to send the pings and receive replies with. - perThreadSetup._testPingProducer = new PingPongProducer(testParameters); - perThreadSetup._testPingProducer.establishConnection(true, true); - perThreadSetup._testPingProducer.start(); - } - - // Attach the per-thread set to the thread. - threadSetup.set(perThreadSetup); - } - catch (Exception e) - { - _logger.warn("There was an exception during per thread setup.", e); - } - } - - /** - * Performs test fixture clean - */ - public void threadTearDown() - { - _logger.debug("public void threadTearDown(): called"); - - try - { - // Get the per thread test fixture. - PerThreadSetup perThreadSetup = threadSetup.get(); - - // Close the pingers so that it cleans up its connection cleanly. - synchronized (this) - { - perThreadSetup._testPingProducer.close(); - // perThreadSetup._testPingBouncer.close(); - } - - // Ensure the per thread fixture is reclaimed. - threadSetup.remove(); - } - catch (JMSException e) - { - _logger.warn("There was an exception during per thread tear down."); - } - } - - protected static class PerThreadSetup - { - /** - * Holds the test ping-pong producer. - */ - private PingPongProducer _testPingProducer; - - /** - * Holds the test ping client. - */ - private PingPongBouncer _testPingBouncer; - } -} +/* + * + * 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.qpid.requestreply; + +import junit.framework.Assert; +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +import org.apache.qpid.junit.extensions.AsymptoticTestCase; +import org.apache.qpid.junit.extensions.util.ParsedProperties; +import org.apache.qpid.junit.extensions.util.TestContextProperties; + +import javax.jms.*; + +/** + * PingPongTestPerf is a full round trip ping test, that has been written with the intention of being scaled up to run + * many times simultaneously to simluate many clients/producer/connections. A full round trip ping sends a message from + * a producer to a conumer, then the consumer replies to the message on a temporary queue. + * + *

    A single run of the test using the default JUnit test runner will result in the sending and timing of the number + * of pings specified by the test size and time how long it takes for all of these to complete. This test may be scaled + * up using a suitable JUnit test runner. See {@link org.apache.qpid.junit.extensions.TKTestRunner} for more + * information on how to do this. + * + *

    The setup/teardown cycle establishes a connection to a broker and sets up a queue to send ping messages to and a + * temporary queue for replies. This setup is only established once for all the test repeats, but each test threads + * gets its own connection/producer/consumer, this is only re-established if the connection is lost. + * + *

    The test cycle is: Connects to a queue, creates a temporary queue, creates messages containing a property that + * is the name of the temporary queue, fires off many messages on the original queue and waits for them all to come + * back on the temporary queue. + * + *

    Configurable test properties: message size, transacted or not, persistent or not. Broker connection details. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    + */ +public class PingPongTestPerf extends AsymptoticTestCase +{ + private static Logger _logger = Logger.getLogger(PingPongTestPerf.class); + + /** Thread local to hold the per-thread test setup fields. */ + ThreadLocal threadSetup = new ThreadLocal(); + + // Set up a property reader to extract the test parameters from. Once ContextualProperties is available in + // the project dependencies, use it to get property overrides for configurable tests and to notify the test runner + // of the test parameters to log with the results. It also providers some basic type parsing convenience methods. + // private Properties testParameters = System.getProperties(); + private ParsedProperties testParameters = + TestContextProperties.getInstance(PingPongProducer.defaults /*System.getProperties()*/); + + public PingPongTestPerf(String name) + { + super(name); + + _logger.debug(testParameters); + + // Sets up the test parameters with defaults. + /*testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME, + Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.MESSAGE_SIZE_PROPNAME, + Integer.toString(PingPongProducer.MESSAGE_SIZE_DEAFULT)); + testParameters.setPropertyIfNull(PingPongProducer.PING_QUEUE_NAME_PROPNAME, + PingPongProducer.PING_QUEUE_NAME_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.PERSISTENT_MODE_PROPNAME, + Boolean.toString(PingPongProducer.PERSISTENT_MODE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.TRANSACTED_PROPNAME, + Boolean.toString(PingPongProducer.TRANSACTED_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.BROKER_PROPNAME, PingPongProducer.BROKER_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.USERNAME_PROPNAME, PingPongProducer.USERNAME_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.PASSWORD_PROPNAME, PingPongProducer.PASSWORD_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.VIRTUAL_HOST_PROPNAME, PingPongProducer.VIRTUAL_HOST_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.VERBOSE_PROPNAME, + Boolean.toString(PingPongProducer.VERBOSE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.RATE_PROPNAME, Integer.toString(PingPongProducer.RATE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.PUBSUB_PROPNAME, + Boolean.toString(PingPongProducer.PUBSUB_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.TX_BATCH_SIZE_PROPNAME, + Integer.toString(PingPongProducer.TX_BATCH_SIZE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.TIMEOUT_PROPNAME, Long.toString(PingPongProducer.TIMEOUT_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.DESTINATION_COUNT_PROPNAME, + Integer.toString(PingPongProducer.DESTINATION_COUNT_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_COMMIT_PROPNAME, + PingPongProducer.FAIL_AFTER_COMMIT_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_COMMIT_PROPNAME, + PingPongProducer.FAIL_BEFORE_COMMIT_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_AFTER_SEND_PROPNAME, + PingPongProducer.FAIL_AFTER_SEND_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_BEFORE_SEND_PROPNAME, + PingPongProducer.FAIL_BEFORE_SEND_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.FAIL_ONCE_PROPNAME, PingPongProducer.FAIL_ONCE_DEFAULT); + testParameters.setPropertyIfNull(PingPongProducer.UNIQUE_DESTS_PROPNAME, + Boolean.toString(PingPongProducer.UNIQUE_DESTS_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.ACK_MODE_PROPNAME, + Integer.toString(PingPongProducer.ACK_MODE_DEFAULT)); + testParameters.setPropertyIfNull(PingPongProducer.PAUSE_AFTER_BATCH_PROPNAME, + PingPongProducer.PAUSE_AFTER_BATCH_DEFAULT);*/ + } + + /** + * Compile all the tests into a test suite. + */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Ping-Pong Performance Tests"); + + // Run performance tests in read committed mode. + suite.addTest(new PingPongTestPerf("testPingPongOk")); + + return suite; + } + + private static void setSystemPropertyIfNull(String propName, String propValue) + { + if (System.getProperty(propName) == null) + { + System.setProperty(propName, propValue); + } + } + + public void testPingPongOk(int numPings) throws Exception + { + // Get the per thread test setup to run the test through. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Generate a sample message. This message is already time stamped and has its reply-to destination set. + Message msg = + perThreadSetup._testPingProducer.getTestMessage(perThreadSetup._testPingProducer.getReplyDestinations().get(0), + testParameters.getPropertyAsInteger(PingPongProducer.MESSAGE_SIZE_PROPNAME), + testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME)); + + // Send the message and wait for a reply. + int numReplies = + perThreadSetup._testPingProducer.pingAndWaitForReply(msg, numPings, PingPongProducer.TIMEOUT_DEFAULT, null); + + // Fail the test if the timeout was exceeded. + if (numReplies != numPings) + { + Assert.fail("The ping timed out, got " + numReplies + " out of " + numPings); + } + } + + /** + * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. + */ + public void threadSetUp() + { + try + { + PerThreadSetup perThreadSetup = new PerThreadSetup(); + + // Extract the test set up paramaeters. + String brokerDetails = testParameters.getProperty(PingPongProducer.BROKER_PROPNAME); + String username = testParameters.getProperty(PingPongProducer.USERNAME_PROPNAME); + String password = testParameters.getProperty(PingPongProducer.PASSWORD_PROPNAME); + String virtualPath = testParameters.getProperty(PingPongProducer.VIRTUAL_HOST_PROPNAME); + String destinationName = testParameters.getProperty(PingPongProducer.PING_QUEUE_NAME_PROPNAME); + boolean persistent = testParameters.getPropertyAsBoolean(PingPongProducer.PERSISTENT_MODE_PROPNAME); + boolean transacted = testParameters.getPropertyAsBoolean(PingPongProducer.TRANSACTED_PROPNAME); + String selector = testParameters.getProperty(PingPongProducer.SELECTOR_PROPNAME); + boolean verbose = testParameters.getPropertyAsBoolean(PingPongProducer.VERBOSE_PROPNAME); + boolean pubsub = testParameters.getPropertyAsBoolean(PingPongProducer.PUBSUB_PROPNAME); + + synchronized (this) + { + // Establish a bounce back client on the ping queue to bounce back the pings. + perThreadSetup._testPingBouncer = + new PingPongBouncer(brokerDetails, username, password, virtualPath, destinationName, persistent, + transacted, selector, verbose, pubsub); + + // Start the connections for client and producer running. + perThreadSetup._testPingBouncer.getConnection().start(); + + // Establish a ping-pong client on the ping queue to send the pings and receive replies with. + perThreadSetup._testPingProducer = new PingPongProducer(testParameters); + perThreadSetup._testPingProducer.establishConnection(true, true); + perThreadSetup._testPingProducer.start(); + } + + // Attach the per-thread set to the thread. + threadSetup.set(perThreadSetup); + } + catch (Exception e) + { + _logger.warn("There was an exception during per thread setup.", e); + } + } + + /** + * Performs test fixture clean + */ + public void threadTearDown() + { + _logger.debug("public void threadTearDown(): called"); + + try + { + // Get the per thread test fixture. + PerThreadSetup perThreadSetup = threadSetup.get(); + + // Close the pingers so that it cleans up its connection cleanly. + synchronized (this) + { + perThreadSetup._testPingProducer.close(); + // perThreadSetup._testPingBouncer.close(); + } + + // Ensure the per thread fixture is reclaimed. + threadSetup.remove(); + } + catch (JMSException e) + { + _logger.warn("There was an exception during per thread tear down."); + } + } + + protected static class PerThreadSetup + { + /** + * Holds the test ping-pong producer. + */ + private PingPongProducer _testPingProducer; + + /** + * Holds the test ping client. + */ + private PingPongBouncer _testPingBouncer; + } +} diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java index f699295b06..0fcb0a8538 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java @@ -1,199 +1,199 @@ -/* - * - * 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.qpid.test.testcases; - -import junit.framework.Test; -import junit.framework.TestSuite; - -import org.apache.log4j.Logger; -import org.apache.log4j.NDC; - -import org.apache.qpid.test.framework.Assertion; -import org.apache.qpid.test.framework.Circuit; -import org.apache.qpid.test.framework.FrameworkBaseCase; -import org.apache.qpid.test.framework.MessagingTestConfigProperties; -import org.apache.qpid.test.framework.sequencers.CircuitFactory; - -import org.apache.qpid.junit.extensions.TestThreadAware; -import org.apache.qpid.junit.extensions.TimingController; -import org.apache.qpid.junit.extensions.TimingControllerAware; -import org.apache.qpid.junit.extensions.util.ParsedProperties; -import org.apache.qpid.junit.extensions.util.TestContextProperties; - -import java.util.LinkedList; - -/** - * MessageThroughputPerf runs a test over a {@link Circuit} controlled by the test parameters. It logs timings of - * the time required to receive samples consisting of batches of messages. - * - *

    - *
    CRC Card
    Responsibilities Collaborations - *
    Measure message throughput accross a test circuit. {@link Circuit} - *
    - * - * @todo Check that all of the messages were sent. Check that the receiving end got the same number of messages as - * the publishing end. - * - * @todo Set this up to run with zero sized tests. Size zero means send forever. Continuous sending to be interrupted - * by completion of the test duration, or shutdown hook when the user presses Ctrl-C. - */ -public class MessageThroughputPerf extends FrameworkBaseCase implements TimingControllerAware, TestThreadAware -{ - /** Used for debugging. */ - private static final Logger log = Logger.getLogger(MessageThroughputPerf.class); - - /** Holds the timing controller, used to log test timings from self-timed tests. */ - private TimingController timingController; - - /** Thread local to hold the per-thread test setup fields. */ - ThreadLocal threadSetup = new ThreadLocal(); - - /** - * Creates a new test case with the specified name. - * - * @param name The test case name. - */ - public MessageThroughputPerf(String name) - { - super(name); - } - - /** - * Performs the a basic P2P test case. - * - * @param numMessages The number of messages to send in the test. - */ - public void testThroughput(int numMessages) - { - log.debug("public void testThroughput(): called"); - - PerThreadSetup setup = threadSetup.get(); - assertNoFailures(setup.testCircuit.test(numMessages, new LinkedList())); - } - - /** - * Should provide a translation from the junit method name of a test to its test case name as known to the test - * clients that will run the test. The purpose of this is to convert the JUnit method name into the correct test - * case name to place into the test invite. For example the method "testP2P" might map onto the interop test case - * name "TC2_BasicP2P". - * - * @param methodName The name of the JUnit test method. - * - * @return The name of the corresponding interop test case. - */ - public String getTestCaseNameForTestMethod(String methodName) - { - log.debug("public String getTestCaseNameForTestMethod(String methodName = " + methodName + "): called"); - - return "DEFAULT_CIRCUIT_TEST"; - } - - /** - * Used by test runners that can supply a {@link org.apache.qpid.junit.extensions.TimingController} to set the - * controller on an aware test. - * - * @param controller The timing controller. - */ - public void setTimingController(TimingController controller) - { - timingController = controller; - } - - /** - * Overrides the parent setUp method so that the in-vm broker creation is not done on a per test basis. - * - * @throws Exception Any exceptions allowed to fall through and fail the test. - */ - protected void setUp() throws Exception - { - NDC.push(getName()); - - testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults); - } - - /** - * Overrides the parent setUp method so that the in-vm broker clean-up is not done on a per test basis. - */ - protected void tearDown() - { - NDC.pop(); - } - - /** - * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. - */ - public void threadSetUp() - { - // Run the test setup tasks. This may create an in-vm broker, if a decorator has injected a task for this. - taskHandler.runSetupTasks(); - - // Get the test parameters, any overrides on the command line will have been applied. - ParsedProperties testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults); - - // Customize the test parameters. - testProps.setProperty("TEST_NAME", "DEFAULT_CIRCUIT_TEST"); - testProps.setProperty(MessagingTestConfigProperties.SEND_DESTINATION_NAME_ROOT_PROPNAME, "testqueue"); - - // Get the test circuit factory to create test circuits and run the standard test procedure through. - CircuitFactory circuitFactory = getCircuitFactory(); - - // Create the test circuit. This projects the circuit onto the available test nodes and connects it up. - Circuit testCircuit = circuitFactory.createCircuit(testProps); - - // Store the test configuration for the thread. - PerThreadSetup setup = new PerThreadSetup(); - setup.testCircuit = testCircuit; - threadSetup.set(setup); - } - - /** - * Called when a test thread is destroyed. - */ - public void threadTearDown() - { - // Run the test teardown tasks. This may destroy the in-vm broker, if a decorator has injected a task for this. - taskHandler.runSetupTasks(); - } - - /** - * Holds the per-thread test configurations. - */ - protected static class PerThreadSetup - { - /** Holds the test circuit to run tests on. */ - Circuit testCircuit; - } - - /** - * Compiles all the tests in this class into a suite. - * - * @return The test suite. - */ - public static Test suite() - { - // Build a new test suite - TestSuite suite = new TestSuite("Qpid Throughput Performance Tests"); - - suite.addTest(new MessageThroughputPerf("testThroughput")); - - return suite; - } -} +/* + * + * 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.qpid.test.testcases; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; + +import org.apache.qpid.test.framework.Assertion; +import org.apache.qpid.test.framework.Circuit; +import org.apache.qpid.test.framework.FrameworkBaseCase; +import org.apache.qpid.test.framework.MessagingTestConfigProperties; +import org.apache.qpid.test.framework.sequencers.CircuitFactory; + +import org.apache.qpid.junit.extensions.TestThreadAware; +import org.apache.qpid.junit.extensions.TimingController; +import org.apache.qpid.junit.extensions.TimingControllerAware; +import org.apache.qpid.junit.extensions.util.ParsedProperties; +import org.apache.qpid.junit.extensions.util.TestContextProperties; + +import java.util.LinkedList; + +/** + * MessageThroughputPerf runs a test over a {@link Circuit} controlled by the test parameters. It logs timings of + * the time required to receive samples consisting of batches of messages. + * + *

    + *
    CRC Card
    Responsibilities Collaborations + *
    Measure message throughput accross a test circuit. {@link Circuit} + *
    + * + * @todo Check that all of the messages were sent. Check that the receiving end got the same number of messages as + * the publishing end. + * + * @todo Set this up to run with zero sized tests. Size zero means send forever. Continuous sending to be interrupted + * by completion of the test duration, or shutdown hook when the user presses Ctrl-C. + */ +public class MessageThroughputPerf extends FrameworkBaseCase implements TimingControllerAware, TestThreadAware +{ + /** Used for debugging. */ + private static final Logger log = Logger.getLogger(MessageThroughputPerf.class); + + /** Holds the timing controller, used to log test timings from self-timed tests. */ + private TimingController timingController; + + /** Thread local to hold the per-thread test setup fields. */ + ThreadLocal threadSetup = new ThreadLocal(); + + /** + * Creates a new test case with the specified name. + * + * @param name The test case name. + */ + public MessageThroughputPerf(String name) + { + super(name); + } + + /** + * Performs the a basic P2P test case. + * + * @param numMessages The number of messages to send in the test. + */ + public void testThroughput(int numMessages) + { + log.debug("public void testThroughput(): called"); + + PerThreadSetup setup = threadSetup.get(); + assertNoFailures(setup.testCircuit.test(numMessages, new LinkedList())); + } + + /** + * Should provide a translation from the junit method name of a test to its test case name as known to the test + * clients that will run the test. The purpose of this is to convert the JUnit method name into the correct test + * case name to place into the test invite. For example the method "testP2P" might map onto the interop test case + * name "TC2_BasicP2P". + * + * @param methodName The name of the JUnit test method. + * + * @return The name of the corresponding interop test case. + */ + public String getTestCaseNameForTestMethod(String methodName) + { + log.debug("public String getTestCaseNameForTestMethod(String methodName = " + methodName + "): called"); + + return "DEFAULT_CIRCUIT_TEST"; + } + + /** + * Used by test runners that can supply a {@link org.apache.qpid.junit.extensions.TimingController} to set the + * controller on an aware test. + * + * @param controller The timing controller. + */ + public void setTimingController(TimingController controller) + { + timingController = controller; + } + + /** + * Overrides the parent setUp method so that the in-vm broker creation is not done on a per test basis. + * + * @throws Exception Any exceptions allowed to fall through and fail the test. + */ + protected void setUp() throws Exception + { + NDC.push(getName()); + + testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults); + } + + /** + * Overrides the parent setUp method so that the in-vm broker clean-up is not done on a per test basis. + */ + protected void tearDown() + { + NDC.pop(); + } + + /** + * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. + */ + public void threadSetUp() + { + // Run the test setup tasks. This may create an in-vm broker, if a decorator has injected a task for this. + taskHandler.runSetupTasks(); + + // Get the test parameters, any overrides on the command line will have been applied. + ParsedProperties testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults); + + // Customize the test parameters. + testProps.setProperty("TEST_NAME", "DEFAULT_CIRCUIT_TEST"); + testProps.setProperty(MessagingTestConfigProperties.SEND_DESTINATION_NAME_ROOT_PROPNAME, "testqueue"); + + // Get the test circuit factory to create test circuits and run the standard test procedure through. + CircuitFactory circuitFactory = getCircuitFactory(); + + // Create the test circuit. This projects the circuit onto the available test nodes and connects it up. + Circuit testCircuit = circuitFactory.createCircuit(testProps); + + // Store the test configuration for the thread. + PerThreadSetup setup = new PerThreadSetup(); + setup.testCircuit = testCircuit; + threadSetup.set(setup); + } + + /** + * Called when a test thread is destroyed. + */ + public void threadTearDown() + { + // Run the test teardown tasks. This may destroy the in-vm broker, if a decorator has injected a task for this. + taskHandler.runSetupTasks(); + } + + /** + * Holds the per-thread test configurations. + */ + protected static class PerThreadSetup + { + /** Holds the test circuit to run tests on. */ + Circuit testCircuit; + } + + /** + * Compiles all the tests in this class into a suite. + * + * @return The test suite. + */ + public static Test suite() + { + // Build a new test suite + TestSuite suite = new TestSuite("Qpid Throughput Performance Tests"); + + suite.addTest(new MessageThroughputPerf("testThroughput")); + + return suite; + } +} -- cgit v1.2.1 From 6acca39fe427c3a92eb35adbd990e343ce32708f Mon Sep 17 00:00:00 2001 From: Arnaud Simon Date: Thu, 22 May 2008 17:16:20 +0000 Subject: QPID-1079: Updated ...test.client tests for using QpidTestCase + move QpidTestCase in main so it is visible form systests git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@659163 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java index 0fcb0a8538..9397db82c9 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java @@ -156,7 +156,7 @@ public class MessageThroughputPerf extends FrameworkBaseCase implements TimingCo CircuitFactory circuitFactory = getCircuitFactory(); // Create the test circuit. This projects the circuit onto the available test nodes and connects it up. - Circuit testCircuit = circuitFactory.createCircuit(testProps); + Circuit testCircuit = circuitFactory.createCircuit(null, testProps); // Store the test configuration for the thread. PerThreadSetup setup = new PerThreadSetup(); -- cgit v1.2.1 From 30102c08501c25704eb0e03c392c487b5e92b8d0 Mon Sep 17 00:00:00 2001 From: Aidan Skinner Date: Tue, 5 Aug 2008 11:10:28 +0000 Subject: QPID-1206: Fix failover and failover tests AMQConnection: remove dead and confusingly misnamed method AMQSession: rename failedOver to failedOverDirty to convey actual usage, only set it if we failed over while dirty. Ewww! BasicMessageConsumer: if we're in client ack mode, mark as dirty when we receive a message PingPongProducer: calculate expected replies properly if we fail after a send or before a commit FailoverTest: test transacted case git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@682672 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/qpid/requestreply/PingPongProducer.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 4d8a736ec8..f994cd138e 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -1673,11 +1673,9 @@ public class PingPongProducer implements Runnable, ExceptionListener */ public int getExpectedNumPings(int numpings) { - // log.debug("public int getExpectedNumPings(int numpings = " + numpings + "): called"); - - // log.debug("Each ping will be received by " + (_isPubSub ? getConsumersPerDestination() : 1) + " consumers."); - - return numpings * (_isPubSub ? getConsumersPerDestination() : 1); + // Wow, I'm freaking sorry about this return here... + return ((_failAfterSend || _failBeforeCommit) ? numpings - 1: numpings) * + (_isPubSub ? getConsumersPerDestination() : 1); } /** -- cgit v1.2.1 From dbc5d989894f52c4e3ca571ee6c9363c84796761 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Thu, 7 Aug 2008 19:25:12 +0000 Subject: QPID-1213: Patch from rgodfrey to refactor AbstractJMSMessage and descendants to move AMQP version specific code into delegates and remove unnecessary conversion between 0-8 and 0-10 objects git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@683683 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/client/message/TestMessageFactory.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java index 64ccb719b6..3ad6c021bd 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java @@ -29,7 +29,6 @@ import javax.jms.ObjectMessage; import javax.jms.StreamMessage; import javax.jms.BytesMessage; import javax.jms.TextMessage; -import javax.jms.Queue; import javax.jms.DeliveryMode; import javax.jms.Destination; @@ -42,10 +41,10 @@ public class TestMessageFactory return session.createTextMessage(createMessagePayload(size)); } - public static JMSTextMessage newJMSTextMessage(int size, String encoding) throws JMSException + public static TextMessage newJMSTextMessage(Session session, int size, String encoding) throws JMSException { - ByteBuffer byteBuffer = (new SimpleByteBufferAllocator()).allocate(size, true); - JMSTextMessage message = new JMSTextMessage(byteBuffer, encoding); + + TextMessage message = session.createTextMessage(); message.clearBody(); message.setText(createMessagePayload(size)); return message; -- cgit v1.2.1 From 573f4ab8b94f50eb7f2dfd434d7301d5fbcc14ce Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 25 Feb 2010 15:16:51 +0000 Subject: QPID-2421 : Augmented Async Performance test to take new 'preFill' value, that puts messages onto the broker destination before the test begins. When running on a non-TX'd producer session the use of the new 'delayBeforeConsume' will pause the client for ms before the test starts, giving the producer session time to flush. This new functionality can be explored with the new 'testWithPreFill' script. The 'numConsumer' parameter was augmented to allow a 0 value which disables all the consumers. This can be seen with the 'fillBroker' script. To complement that a new 'consumeOnly' boolean was added to disable sending messages. This can be seen with the 'drainBroker' scripts. All scripts are located in java/perftests/etc/scripts Merged from 0.5.x-dev commit r916304 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@916318 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/PingAsyncTestPerf.java | 17 +++- .../java/org/apache/qpid/ping/PingTestPerf.java | 62 +++++++++++- .../apache/qpid/requestreply/PingPongProducer.java | 111 +++++++++++++++++++-- 3 files changed, 177 insertions(+), 13 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java index 89fc805a34..d8fea85477 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java @@ -133,8 +133,11 @@ public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerA { // _logger.debug("public void testAsyncPingOk(int numPings): called"); + // get prefill count to update the expected count + int preFill = testParameters.getPropertyAsInteger(PingPongProducer.PREFILL_PROPNAME); + // Ensure that at least one ping was requeusted. - if (numPings == 0) + if (numPings + preFill == 0) { _logger.error("Number of pings requested was zero."); fail("Number of pings requested was zero."); @@ -149,16 +152,24 @@ public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerA // String messageCorrelationId = perThreadSetup._correlationId; // _logger.debug("messageCorrelationId = " + messageCorrelationId); + // Initialize the count and timing controller for the new correlation id. PerCorrelationId perCorrelationId = new PerCorrelationId(); TimingController tc = getTimingController().getControllerForCurrentThread(); perCorrelationId._tc = tc; - perCorrelationId._expectedCount = pingClient.getExpectedNumPings(numPings); + perCorrelationId._expectedCount = pingClient.getExpectedNumPings(numPings + preFill); perCorrelationIds.put(perThreadSetup._correlationId, perCorrelationId); + // Start the client that will have been paused due to preFill requirement. + // or if we have not yet started client because messages are sitting on broker. + if (preFill > 0 || testParameters.getPropertyAsBoolean(PingPongProducer.CONSUME_ONLY_PROPNAME)) + { + pingClient.start(); + } + // Send the requested number of messages, and wait until they have all been received. long timeout = Long.parseLong(testParameters.getProperty(PingPongProducer.TIMEOUT_PROPNAME)); - int numReplies = pingClient.pingAndWaitForReply(null, numPings, timeout, perThreadSetup._correlationId); + int numReplies = pingClient.pingAndWaitForReply(null, numPings , preFill, timeout, perThreadSetup._correlationId); // Check that all the replies were received and log a fail if they were not. if (numReplies < perCorrelationId._expectedCount) diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java index 94b8ea662e..0f9603303b 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java @@ -141,9 +141,65 @@ public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware perThreadSetup._pingClient = new PingClient(testParameters); perThreadSetup._pingClient.establishConnection(true, true); } - // Start the client connection - perThreadSetup._pingClient.start(); + // Prefill the broker unless we are in consume only mode. + int preFill = testParameters.getPropertyAsInteger(PingPongProducer.PREFILL_PROPNAME); + if (!testParameters.getPropertyAsBoolean(PingPongProducer.CONSUME_ONLY_PROPNAME) && preFill > 0) + { + // Manually set the correlation ID to 1. This is not ideal but it is the + // value that the main test loop will use. + perThreadSetup._pingClient.pingNoWaitForReply(null, preFill, "1"); + + // Note with a large preFill and non-tx session the messages will be + // rapidly pushed in to the mina buffers. OOM's are a real risk here. + // Should perhaps consider using a TX session for the prefill. + + long delayBeforeConsume = testParameters.getPropertyAsLong(PingPongProducer.DELAY_BEFORE_CONSUME_PROPNAME); + + // Only delay if we have consumers and a delayBeforeConsume + if ((testParameters.getPropertyAsInteger(PingPongProducer.NUM_CONSUMERS_PROPNAME) > 0) + && delayBeforeConsume > 0) + { + + boolean verbose = testParameters.getPropertyAsBoolean(PingPongProducer.VERBOSE_PROPNAME); + // Only do logging if in verbose mode. + if (verbose) + { + if (delayBeforeConsume > 60000) + { + long minutes = delayBeforeConsume / 60000; + long seconds = (delayBeforeConsume - (minutes * 60000)) / 1000; + long ms = delayBeforeConsume - (minutes * 60000) - (seconds * 1000); + _logger.info("Delaying for " + minutes + "m " + seconds + "s " + ms + "ms before starting test."); + } + else + { + _logger.info("Delaying for " + delayBeforeConsume + "ms before starting test."); + } + } + + Thread.sleep(delayBeforeConsume); + + if (verbose) + { + _logger.info("Starting Test."); + } + } + + // We can't start the client's here as the test client has not yet been configured to receieve messages. + // only when the test method is executed will the correlationID map be set up and ready to consume + // the messages we have sent here. + } + else //Only start the consumer if we are not preFilling. + { + // Only start the consumer if we don't have messages waiting to be received. + // we need to set up the correlationID mapping first + if (!testParameters.getPropertyAsBoolean(PingPongProducer.CONSUME_ONLY_PROPNAME)) + { + // Start the client connection + perThreadSetup._pingClient.start(); + } + } // Attach the per-thread set to the thread. threadSetup.set(perThreadSetup); } @@ -157,7 +213,7 @@ public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware * Performs test fixture clean */ public void threadTearDown() - { + { _logger.debug("public void threadTearDown(): called"); try diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index f994cd138e..e3769e415e 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -324,6 +324,25 @@ public class PingPongProducer implements Runnable, ExceptionListener /** Holds the name of the property to store nanosecond timestamps in ping messages with. */ public static final String MESSAGE_TIMESTAMP_PROPNAME = "timestamp"; + /** Holds the name of the property to get the number of message to prefill the broker with before starting the main test. */ + public static final String PREFILL_PROPNAME = "preFill"; + + /** Defines the default value for the number of messages to prefill. 0,default, no messages. */ + public static final int PREFILL_DEFAULT = 0; + + /** Holds the name of the property to get the delay to wait in ms before starting the main test after having prefilled. */ + public static final String DELAY_BEFORE_CONSUME_PROPNAME = "delayBeforeConsume"; + + /** Defines the default value for delay in ms to wait before starting thet test run. 0,default, no delay. */ + public static final long DELAY_BEFORE_CONSUME = 0; + + /** Holds the name of the property to get when no messasges should be sent. */ + public static final String CONSUME_ONLY_PROPNAME = "consumeOnly"; + + /** Defines the default value of the consumeOnly flag to use when publishing messages is not desired. */ + public static final boolean CONSUME_ONLY_DEFAULT = false; + + /** Holds the default configuration properties. */ public static ParsedProperties defaults = new ParsedProperties(); @@ -360,6 +379,9 @@ public class PingPongProducer implements Runnable, ExceptionListener defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT); defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT); defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT); + defaults.setPropertyIfNull(PREFILL_PROPNAME, PREFILL_DEFAULT); + defaults.setPropertyIfNull(DELAY_BEFORE_CONSUME_PROPNAME, DELAY_BEFORE_CONSUME); + defaults.setPropertyIfNull(CONSUME_ONLY_PROPNAME, CONSUME_ONLY_DEFAULT); } /** Allows setting of client ID on the connection, rather than through the connection URL. */ @@ -455,6 +477,24 @@ public class PingPongProducer implements Runnable, ExceptionListener */ protected int _maxPendingSize; + /** + * Holds the number of messages to send during the setup phase, before the clients start consuming. + */ + private Integer _preFill; + + /** + * Holds the time in ms to wait after preFilling before starting thet test. + */ + private Long _delayBeforeConsume; + + /** + * Holds a boolean value of wither this test should just consume, i.e. skips + * sending messages, but still expects to receive the specified number. + * Use in conjuction with numConsumers=0 to fill the broker. + */ + private boolean _consumeOnly; + + /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); @@ -588,6 +628,9 @@ public class PingPongProducer implements Runnable, ExceptionListener _ackMode = _transacted ? 0 : properties.getPropertyAsInteger(ACK_MODE_PROPNAME); _consAckMode = _consTransacted ? 0 : properties.getPropertyAsInteger(CONSUMER_ACK_MODE_PROPNAME); _maxPendingSize = properties.getPropertyAsInteger(MAX_PENDING_PROPNAME); + _preFill = properties.getPropertyAsInteger(PREFILL_PROPNAME); + _delayBeforeConsume = properties.getPropertyAsLong(DELAY_BEFORE_CONSUME_PROPNAME); + _consumeOnly = properties.getPropertyAsBoolean(CONSUME_ONLY_PROPNAME); // Check that one or more destinations were specified. if (_noOfDestinations < 1) @@ -638,7 +681,10 @@ public class PingPongProducer implements Runnable, ExceptionListener } // Create the destinations to send pings to and receive replies from. - _replyDestination = _consumerSession[0].createTemporaryQueue(); + if (_noOfConsumers > 0) + { + _replyDestination = _consumerSession[0].createTemporaryQueue(); + } createPingDestinations(_noOfDestinations, _selector, _destinationName, _isUnique, _isDurable); // Create the message producer only if instructed to. @@ -871,6 +917,14 @@ public class PingPongProducer implements Runnable, ExceptionListener { _consumer = new MessageConsumer[_noOfConsumers]; + // If we don't have consumers then ensure we have created the + // destination. + if (_noOfConsumers == 0) + { + _producerSession.createConsumer(destination, selector, + NO_LOCAL_DEFAULT).close(); + } + for (int i = 0; i < _noOfConsumers; i++) { // Create a consumer for the destination and set this pinger to listen to its messages. @@ -980,6 +1034,11 @@ public class PingPongProducer implements Runnable, ExceptionListener // When running in client ack mode, an ack is done instead of a commit, on the commit batch // size boundaries. long commitCount = _isPubSub ? remainingCount : (remainingCount / _noOfConsumers); + // _noOfConsumers can be set to 0 on the command line but we will not get here to + // divide by 0 as this is executed by the onMessage code when a message is recevied. + // no consumers means no message reception. + + // log.debug("commitCount = " + commitCount); if ((commitCount % _txBatchSize) == 0) @@ -1014,6 +1073,7 @@ public class PingPongProducer implements Runnable, ExceptionListener else { log.warn("Got unexpected message with correlationId: " + correlationID); + log.warn("Map contains:" + perCorrelationIds.entrySet()); } } else @@ -1037,13 +1097,18 @@ public class PingPongProducer implements Runnable, ExceptionListener * before a reply arrives, then a null reply is returned from this method. This method allows the caller to specify * the correlation id. * + * Can be augmented through a pre-fill property (PingPongProducer.PREFILL_PROPNAME) that will populate the destination + * with a set number of messages so the total pings sent and therefore expected will be PREFILL + numPings. + * + * If pre-fill is specified then the consumers will start paused to allow the prefilling to occur. + * * @param message The message to send. If this is null, one is generated. * @param numPings The number of ping messages to send. * @param timeout The timeout in milliseconds. * @param messageCorrelationId The message correlation id. If this is null, one is generated. * * @return The number of replies received. This may be less than the number sent if the timeout terminated the wait - * for all prematurely. + * for all prematurely. If we are running in noConsumer=0 so send only mode then it will return the no msgs sent. * * @throws JMSException All underlying JMSExceptions are allowed to fall through. * @throws InterruptedException When interrupted by a timeout @@ -1051,6 +1116,16 @@ public class PingPongProducer implements Runnable, ExceptionListener public int pingAndWaitForReply(Message message, int numPings, long timeout, String messageCorrelationId) throws JMSException, InterruptedException { + return pingAndWaitForReply(message, numPings, 0, timeout, messageCorrelationId); + } + + public int pingAndWaitForReply(Message message, int numPings, int preFill, long timeout, String messageCorrelationId) + throws JMSException, InterruptedException + { + + // If we are runnning a consumeOnly test then don't send any messages + + /*log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ @@ -1071,29 +1146,41 @@ public class PingPongProducer implements Runnable, ExceptionListener // countdown needs to be done before the chained listener can be called. PerCorrelationId perCorrelationId = new PerCorrelationId(); - perCorrelationId.trafficLight = new CountDownLatch(getExpectedNumPings(numPings) + 1); + int totalPingsRequested = numPings + preFill; + perCorrelationId.trafficLight = new CountDownLatch(getExpectedNumPings(totalPingsRequested) + 1); perCorrelationIds.put(messageCorrelationId, perCorrelationId); // Set up the current time as the start time for pinging on the correlation id. This is used to determine // timeouts. perCorrelationId.timeOutStart = System.nanoTime(); - // Send the specifed number of messages. + // Send the specifed number of messages for this test pingNoWaitForReply(message, numPings, messageCorrelationId); boolean timedOut; boolean allMessagesReceived; int numReplies; + // We don't have a consumer so don't try and wait for the messages. + // this does mean that if the producerSession is !TXed then we may + // get to exit before all msgs have been received. + // + // Return the number of requested messages, this will let the test + // report a pass. + if (_noOfConsumers == 0) + { + return totalPingsRequested; + } + do { // Block the current thread until replies to all the messages are received, or it times out. perCorrelationId.trafficLight.await(timeout, TimeUnit.MILLISECONDS); // Work out how many replies were receieved. - numReplies = getExpectedNumPings(numPings) - (int) perCorrelationId.trafficLight.getCount(); + numReplies = getExpectedNumPings(totalPingsRequested) - (int) perCorrelationId.trafficLight.getCount(); - allMessagesReceived = numReplies == getExpectedNumPings(numPings); + allMessagesReceived = numReplies == getExpectedNumPings(totalPingsRequested); // log.debug("numReplies = " + numReplies); // log.debug("allMessagesReceived = " + allMessagesReceived); @@ -1108,7 +1195,7 @@ public class PingPongProducer implements Runnable, ExceptionListener } while (!timedOut && !allMessagesReceived); - if ((numReplies < getExpectedNumPings(numPings)) && _verbose) + if ((numReplies < getExpectedNumPings(totalPingsRequested)) && _verbose) { log.info("Timed out (" + timeout + " ms) before all replies received on id, " + messageCorrelationId); } @@ -1146,6 +1233,12 @@ public class PingPongProducer implements Runnable, ExceptionListener /*log.debug("public void pingNoWaitForReply(Message message, int numPings = " + numPings + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ + // If we are runnning a consumeOnly test then don't send any messages + if (_consumeOnly) + { + return; + } + if (message == null) { message = getTestMessage(getReplyDestinations().get(0), _messageSize, _persistent); @@ -1667,6 +1760,10 @@ public class PingPongProducer implements Runnable, ExceptionListener /** * Calculates how many pings are expected to be received for the given number sent. * + * Note : that if you have set noConsumers to 0 then this will also return 0 + * in the case of PubSub testing. This is correct as without consumers there + * will be no-one to receive the sent messages so they will be unable to respond. + * * @param numpings The number of pings that will be sent. * * @return The number that should be received, for the test to pass. -- cgit v1.2.1 From d6d234e73dbcface912acbf9a34d3e1964042faf Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 25 Feb 2010 15:44:51 +0000 Subject: QPID-2421 : Update to expose the PingClient count so we can set the correlationID correctly for test with > 1 -c[] value. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@916327 13f79535-47bb-0310-9956-ffa450edef68 --- .../perftests/src/main/java/org/apache/qpid/ping/PingClient.java | 5 +++++ .../perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java index 0afec83b19..dcfc67d4fc 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingClient.java @@ -104,4 +104,9 @@ public class PingClient extends PingPongProducer return _pingClientCount * _noOfConsumers; } } + + public int getClientCount() + { + return _pingClientCount; + } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java index 0f9603303b..4c5df0a471 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java @@ -148,7 +148,7 @@ public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware { // Manually set the correlation ID to 1. This is not ideal but it is the // value that the main test loop will use. - perThreadSetup._pingClient.pingNoWaitForReply(null, preFill, "1"); + perThreadSetup._pingClient.pingNoWaitForReply(null, preFill, String.valueOf(perThreadSetup._pingClient.getClientCount())); // Note with a large preFill and non-tx session the messages will be // rapidly pushed in to the mina buffers. OOM's are a real risk here. -- cgit v1.2.1 From 46cbccacaf45190937edac7c82df041d8c8086cc Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 3 Mar 2010 16:34:19 +0000 Subject: QPID-2417: add a volume test for transient message delivery using topics + selectors git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@918556 13f79535-47bb-0310-9956-ffa450edef68 --- .../TopicWithSelectorsTransientVolumeTest.java | 324 +++++++++++++++++++++ .../apache/qpid/topic/topicselectors.properties | 24 ++ 2 files changed, 348 insertions(+) create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java create mode 100644 qpid/java/perftests/src/main/java/org/apache/qpid/topic/topicselectors.properties (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java new file mode 100644 index 0000000000..728b9d5872 --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java @@ -0,0 +1,324 @@ +package org.apache.qpid.topic; + +import java.util.ArrayList; +import java.util.HashMap; + +import javax.jms.BytesMessage; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; +import javax.naming.NamingException; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.test.utils.QpidTestCase; + +public class TopicWithSelectorsTransientVolumeTest extends QpidTestCase +{ + private static final int NUM_MSG_PER_ITERATION = 50;//must be a multiple of 10 + private static final int NUM_ITERATIONS = 1000; + + private static final int NUM_CONSUMERS = 50; + private static final int MSG_SIZE = 1024; + private static final byte[] BYTE_ARRAY = new byte[MSG_SIZE]; + + ArrayList _subscribers = new ArrayList(); + HashMap _queueMsgCounts = new HashMap(); + + private final static Object _lock=new Object(); + private boolean _producerFailed; + private static int _finishedCount; + private static int _failedCount; + + protected void setUp() throws Exception + { + super.setUp(); + init(); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + private void init() + { + _finishedCount = 0; + _failedCount = 0; + _producerFailed = false; + _subscribers.clear(); + _queueMsgCounts.clear(); + } + + + private Message createMessage(Session session) throws JMSException + { + BytesMessage message = session.createBytesMessage(); + message.writeBytes(BYTE_ARRAY); + + return message; + } + + /** + * 1 Topic with 50 subscribers using a selector, and 1 producer sending 50,000 1K messages with 90% selector success ratio. + */ + public void test50SubscribersWith90PercentMatched() throws Exception + { + Topic topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME, "test50ConsumersWith10PercentUnmatched"); + + System.out.println("Creating consumers"); + + MyMessageSubscriber sub; + + for(int i=1; i <= NUM_CONSUMERS; i++) + { + sub = new MyMessageSubscriber(topic, "consumer" + i, ((9 * NUM_MSG_PER_ITERATION * NUM_ITERATIONS) / 10)); + _subscribers.add(sub); + } + + System.out.println("Starting consumers"); + for(MyMessageSubscriber s: _subscribers) + { + Thread consumer = new Thread(s); + consumer.start(); + } + + System.out.println("Creating producer"); + MyMessageProducer prod = new MyMessageProducer(topic); + + long startTime = System.currentTimeMillis(); + + System.out.println("Starting producer"); + Thread producer = new Thread(prod); + producer.start(); + + + // Wait for all the messageConsumers to have finished or failed + synchronized (_lock) + { + while (_finishedCount + _failedCount < NUM_CONSUMERS) + { + try + { + _lock.wait(); + } + catch (InterruptedException e) + { + //ignore + } + } + } + + long endTime = System.currentTimeMillis(); + System.out.println("Elapsed time for messaging: " + (endTime-startTime) + "ms"); + + assertFalse("Producer failed to send all messages", _producerFailed); + + //check if all messages received by consumers, or if there were failures + if (_finishedCount != NUM_CONSUMERS) + { + fail(_failedCount + " consumers did not recieve all their expected messages"); + } + + //check if all queue depths were 0 + for(String consumer: _queueMsgCounts.keySet()) + { + long depth = _queueMsgCounts.get(consumer); + assertEquals(consumer + " subscription queue msg count was not 0", 0, depth); + } + + } + + private class MyMessageProducer implements Runnable + { + private TopicConnection _connection; + private TopicSession _session; + private TopicPublisher _messagePublisher; + + public MyMessageProducer(Topic topic) throws JMSException, NamingException + { + _connection = (TopicConnection) getConnection(); + _session = (TopicSession) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _messagePublisher = _session.createPublisher(topic); + } + + public void run() + { + try + { + for(int iter = 0; iter < NUM_ITERATIONS; iter++) + { + int i = 0; + + //send 90% matching messages + for (; i < (9 * NUM_MSG_PER_ITERATION)/10; i++) + { + Message message = createMessage(_session); + message.setStringProperty("testprop", "true"); + + _messagePublisher.publish(message, DeliveryMode.NON_PERSISTENT, + Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); + + Thread.yield(); + } + + //send remaining 10% non-matching messages + for (; i < NUM_MSG_PER_ITERATION; i++) + { + Message message = _session.createMessage(); + message.setStringProperty("testprop", "false"); + + _messagePublisher.publish(message, DeliveryMode.NON_PERSISTENT, + Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); + + Thread.yield(); + } + } + + } + catch (Exception exp) + { + System.out.println("producer: caught an exception, probably exiting before all messages sent"); + exp.printStackTrace(); + synchronized (_lock) + { + _producerFailed=true; + _lock.notifyAll(); + } + } + } + } + + + private class MyMessageSubscriber implements Runnable + { + /* The topic this subscriber is subscribing to */ + private Topic _topic; + private String _consumerName; + private int _outstandingMsgCount; + private TopicConnection _connection; + private TopicSession _session; + private TopicSubscriber _durSub; + + public MyMessageSubscriber(Topic topic, String consumerName, int messageCount) throws JMSException, NamingException + { + _outstandingMsgCount = messageCount; + _topic=topic; + _consumerName = consumerName; + _connection = (TopicConnection) getConnection(); + _session = (TopicSession) _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _durSub = _session.createDurableSubscriber(_topic, _consumerName,"testprop='true'", false); + _connection.start(); + } + + public void run() + { + + boolean failed = false; + do + { + Message m = null; + try + { + m = _durSub.receive(10000); + } + catch (JMSException exp) + { + System.out.println(_consumerName + ": caught an exception handling a received message"); + exp.printStackTrace(); + + failed = true; + break; + } + + Thread.yield(); + + _outstandingMsgCount--; + + if(_outstandingMsgCount % 500 == 0) + { + System.out.println(_consumerName + ": outstanding message count: " + _outstandingMsgCount); + } + + if(m == null) + { + if(_outstandingMsgCount != 0) + { + failed = true; + } + break; + } + } + while(_outstandingMsgCount > 0); + + System.out.println(_consumerName + ": outstanding message count: " + _outstandingMsgCount); + + try + { + AMQQueue subcriptionQueue = new AMQQueue(ExchangeDefaults.TOPIC_EXCHANGE_NAME,"clientid" + ":" + _consumerName); + + ((AMQSession)_session).sync(); + Long depth = ((AMQSession)_session).getQueueDepth(subcriptionQueue); + _queueMsgCounts.put(_consumerName, depth); + + System.out.println(_consumerName + ": completion queue msg count: " + depth); + } + catch (AMQException exp) + { + System.out.println(_consumerName + ": caught an exception determining completion queue depth"); + exp.printStackTrace(); + } + finally + { + try + { + _session.unsubscribe(_consumerName); + } + catch (JMSException e) + { + System.out.println(_consumerName + ": caught an exception whilst unsubscribing"); + e.printStackTrace(); + } + } + + synchronized (_lock) + { + if (_outstandingMsgCount == 0 && !failed) + { + _finishedCount++; + System.out.println(_consumerName + ": finished"); + } + else + { + _failedCount++; + System.out.println(_consumerName + ": failed"); + } + _lock.notifyAll(); + } + + } + } + + //helper method to allow easily running against an external standalone broker +// public static void main(String[] args) throws Exception +// { +// System.setProperty("broker.config", "/dev/null"); +// System.setProperty("broker", "external"); +// System.setProperty("java.naming.factory.initial", "org.apache.qpid.jndi.PropertiesFileInitialContextFactory"); +// System.setProperty("java.naming.provider.url", "test-profiles/test-provider.properties"); +// +// TopicWithSelectorsTransientVolumeTest test = new TopicWithSelectorsTransientVolumeTest(); +// test.init(); +// test.test50SubscribersWith90PercentMatched(); +// test.tearDown(); +// } +} \ No newline at end of file diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/topicselectors.properties b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/topicselectors.properties new file mode 100644 index 0000000000..1f572af58a --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/topicselectors.properties @@ -0,0 +1,24 @@ +# +# 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. +# +java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory + + +# register some connection factories +# connectionfactory.[jndiname] = [ConnectionURL] +connectionfactory.default = amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672' \ No newline at end of file -- cgit v1.2.1 From b1bffee58eeadcd846dd300fcb26ccf3e7250a10 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 12 Apr 2010 15:42:47 +0000 Subject: QPID-2425 : Augmented JUnit-Toolkit to emit latency information already gathed by the PingAsyncTestPerf for each batch. Merged from 0.5.x-dev r 917464 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@933283 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java index d8fea85477..9ed9fea299 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java @@ -228,6 +228,9 @@ public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerA /** The test results logging batch size. */ int _batchSize; + /** The latency recoreded for the batch */ + private long _batchLatency = 0; + /** * Creates a results listener on the specified batch size. * @@ -250,6 +253,8 @@ public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerA */ public void onMessage(Message message, int remainingCount, long latency) throws JMSException { + // Record the latency for the whole batch + _batchLatency += latency; // Check if a batch boundary has been crossed. if ((remainingCount % _batchSize) == 0) { @@ -278,7 +283,11 @@ public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerA // Register a test result for the correlation id. try { - tc.completeTest(true, receivedInBatch); + // Record the total latency for the batch. + // if batchSize=1 then this will just be the message latency + tc.completeTest(true, receivedInBatch, null, _batchLatency); + // Reset latency + _batchLatency = 0; } catch (InterruptedException e) { -- cgit v1.2.1 From d96f592d18e80cab8f73c740b6cb14d612befe36 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 12 Apr 2010 15:43:36 +0000 Subject: QPID-2421 : Fixed preFill when numConsumers > 1. This requried the introduction of a new phase in TestThreadAware : postThreadSetup. This ensures that all the threads have correctly setup their clients and so registered their topic subscribers. We can then preFill in the postThreadSetup and reliably receive the data from each of the client's publishers. Added new sendOnly parameter to allow send only testing with topics where numConsumers must be set. Merged from 0.5.x-dev rev 920389 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@933286 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/ping/PingAsyncTestPerf.java | 18 ++++-- .../java/org/apache/qpid/ping/PingTestPerf.java | 71 +++++++++++++++------- .../apache/qpid/requestreply/PingPongProducer.java | 58 ++++++++++++------ .../qpid/test/testcases/MessageThroughputPerf.java | 8 +++ 4 files changed, 110 insertions(+), 45 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java index 9ed9fea299..dc78276edd 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingAsyncTestPerf.java @@ -154,15 +154,25 @@ public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerA // Initialize the count and timing controller for the new correlation id. + // This perCorrelationId is only used for controlling the test. + // The PingClient itself uses its own perCorrelationId see in PingPongProducer PerCorrelationId perCorrelationId = new PerCorrelationId(); TimingController tc = getTimingController().getControllerForCurrentThread(); perCorrelationId._tc = tc; perCorrelationId._expectedCount = pingClient.getExpectedNumPings(numPings + preFill); perCorrelationIds.put(perThreadSetup._correlationId, perCorrelationId); - // Start the client that will have been paused due to preFill requirement. - // or if we have not yet started client because messages are sitting on broker. - if (preFill > 0 || testParameters.getPropertyAsBoolean(PingPongProducer.CONSUME_ONLY_PROPNAME)) + // Must be called before pingAndWaitForReply to setup the CorrelationID. + // This is required because pingClient.start() will start all client threads + // This means that the CorrelationID must be registered before hand. + pingClient.setupCorrelationID(perThreadSetup._correlationId, perCorrelationId._expectedCount); + + // Start the client connection if: + // 1) we are not in a SEND_ONLY test. + // 2) if we have not yet started client because messages are sitting on broker. + // This is either due to a preFill or a consume only test. + if (!testParameters.getPropertyAsBoolean(PingPongProducer.SEND_ONLY_PROPNAME) && + (preFill > 0 || testParameters.getPropertyAsBoolean(PingPongProducer.CONSUME_ONLY_PROPNAME))) { pingClient.start(); } @@ -285,7 +295,7 @@ public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerA { // Record the total latency for the batch. // if batchSize=1 then this will just be the message latency - tc.completeTest(true, receivedInBatch, null, _batchLatency); + tc.completeTest(true, receivedInBatch, null, _batchSize == 1 ? latency : _batchLatency); // Reset latency _batchLatency = 0; } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java index 4c5df0a471..cf16abc596 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingTestPerf.java @@ -122,9 +122,7 @@ public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware } } - /** - * Performs test fixture creation on a per thread basis. This will only be called once for each test thread. - */ + /** Performs test fixture creation on a per thread basis. This will only be called once for each test thread. */ public void threadSetUp() { _logger.debug("public void threadSetUp(): called"); @@ -142,9 +140,28 @@ public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware perThreadSetup._pingClient.establishConnection(true, true); } - // Prefill the broker unless we are in consume only mode. - int preFill = testParameters.getPropertyAsInteger(PingPongProducer.PREFILL_PROPNAME); - if (!testParameters.getPropertyAsBoolean(PingPongProducer.CONSUME_ONLY_PROPNAME) && preFill > 0) + // Attach the per-thread set to the thread. + threadSetup.set(perThreadSetup); + } + catch (Exception e) + { + _logger.warn("There was an exception during per thread setup.", e); + } + } + + /** + * Called after all threads have completed their setup. + */ + public void postThreadSetUp() + { + _logger.debug("public void postThreadSetUp(): called"); + + PerThreadSetup perThreadSetup = threadSetup.get(); + // Prefill the broker unless we are in consume only mode. + int preFill = testParameters.getPropertyAsInteger(PingPongProducer.PREFILL_PROPNAME); + if (!testParameters.getPropertyAsBoolean(PingPongProducer.CONSUME_ONLY_PROPNAME) && preFill > 0) + { + try { // Manually set the correlation ID to 1. This is not ideal but it is the // value that the main test loop will use. @@ -156,8 +173,12 @@ public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware long delayBeforeConsume = testParameters.getPropertyAsLong(PingPongProducer.DELAY_BEFORE_CONSUME_PROPNAME); - // Only delay if we have consumers and a delayBeforeConsume - if ((testParameters.getPropertyAsInteger(PingPongProducer.NUM_CONSUMERS_PROPNAME) > 0) + // Only delay if we are + // not doing send only + // and we have consumers + // and a delayBeforeConsume + if (!(testParameters.getPropertyAsBoolean(PingPongProducer.SEND_ONLY_PROPNAME)) + && (testParameters.getPropertyAsInteger(PingPongProducer.NUM_CONSUMERS_PROPNAME) > 0) && delayBeforeConsume > 0) { @@ -170,11 +191,11 @@ public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware long minutes = delayBeforeConsume / 60000; long seconds = (delayBeforeConsume - (minutes * 60000)) / 1000; long ms = delayBeforeConsume - (minutes * 60000) - (seconds * 1000); - _logger.info("Delaying for " + minutes + "m " + seconds + "s " + ms + "ms before starting test."); + _logger.info("Delaying for " + minutes + "m " + seconds + "s " + ms + "ms before starting test."); } else { - _logger.info("Delaying for " + delayBeforeConsume + "ms before starting test."); + _logger.info("Delaying for " + delayBeforeConsume + "ms before starting test."); } } @@ -190,22 +211,30 @@ public class PingTestPerf extends AsymptoticTestCase implements TestThreadAware // only when the test method is executed will the correlationID map be set up and ready to consume // the messages we have sent here. } - else //Only start the consumer if we are not preFilling. + catch (Exception e) { - // Only start the consumer if we don't have messages waiting to be received. - // we need to set up the correlationID mapping first - if (!testParameters.getPropertyAsBoolean(PingPongProducer.CONSUME_ONLY_PROPNAME)) + _logger.warn("There was an exception during per thread setup.", e); + } + } + else //Only start the consumer if we are not preFilling. + { + // Start the consumers, unless we have data on the broker + // already this is signified by being in consume_only, we will + // start the clients after setting up the correlation IDs. + // We should also not start the clients if we are in Send only + if (!testParameters.getPropertyAsBoolean(PingPongProducer.CONSUME_ONLY_PROPNAME) && + !(testParameters.getPropertyAsBoolean(PingPongProducer.SEND_ONLY_PROPNAME))) + { + // Start the client connection + try { - // Start the client connection perThreadSetup._pingClient.start(); } + catch (JMSException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } } - // Attach the per-thread set to the thread. - threadSetup.set(perThreadSetup); - } - catch (Exception e) - { - _logger.warn("There was an exception during per thread setup.", e); } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index e3769e415e..0bf952b7e1 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -342,6 +342,11 @@ public class PingPongProducer implements Runnable, ExceptionListener /** Defines the default value of the consumeOnly flag to use when publishing messages is not desired. */ public static final boolean CONSUME_ONLY_DEFAULT = false; + /** Holds the name of the property to get when no messasges should be sent. */ + public static final String SEND_ONLY_PROPNAME = "sendOnly"; + + /** Defines the default value of the consumeOnly flag to use when publishing messages is not desired. */ + public static final boolean SEND_ONLY_DEFAULT = false; /** Holds the default configuration properties. */ public static ParsedProperties defaults = new ParsedProperties(); @@ -381,7 +386,8 @@ public class PingPongProducer implements Runnable, ExceptionListener defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT); defaults.setPropertyIfNull(PREFILL_PROPNAME, PREFILL_DEFAULT); defaults.setPropertyIfNull(DELAY_BEFORE_CONSUME_PROPNAME, DELAY_BEFORE_CONSUME); - defaults.setPropertyIfNull(CONSUME_ONLY_PROPNAME, CONSUME_ONLY_DEFAULT); + defaults.setPropertyIfNull(CONSUME_ONLY_PROPNAME, CONSUME_ONLY_DEFAULT); + defaults.setPropertyIfNull(SEND_ONLY_PROPNAME, SEND_ONLY_DEFAULT); } /** Allows setting of client ID on the connection, rather than through the connection URL. */ @@ -490,10 +496,15 @@ public class PingPongProducer implements Runnable, ExceptionListener /** * Holds a boolean value of wither this test should just consume, i.e. skips * sending messages, but still expects to receive the specified number. - * Use in conjuction with numConsumers=0 to fill the broker. */ private boolean _consumeOnly; + /** + * Holds a boolean value of wither this test should just send, i.e. skips + * consuming messages, but still creates clients just doesn't start them. + */ + private boolean _sendOnly; + /** A source for providing sequential unique correlation ids. These will be unique within the same JVM. */ private static AtomicLong _correlationIdGenerator = new AtomicLong(0L); @@ -631,6 +642,7 @@ public class PingPongProducer implements Runnable, ExceptionListener _preFill = properties.getPropertyAsInteger(PREFILL_PROPNAME); _delayBeforeConsume = properties.getPropertyAsLong(DELAY_BEFORE_CONSUME_PROPNAME); _consumeOnly = properties.getPropertyAsBoolean(CONSUME_ONLY_PROPNAME); + _sendOnly = properties.getPropertyAsBoolean(SEND_ONLY_PROPNAME); // Check that one or more destinations were specified. if (_noOfDestinations < 1) @@ -1072,8 +1084,8 @@ public class PingPongProducer implements Runnable, ExceptionListener } else { - log.warn("Got unexpected message with correlationId: " + correlationID); - log.warn("Map contains:" + perCorrelationIds.entrySet()); + log.warn(consumerNo + " Got unexpected message with correlationId: " + correlationID); + log.warn(consumerNo + " Map contains:" + perCorrelationIds.entrySet()); } } else @@ -1092,6 +1104,21 @@ public class PingPongProducer implements Runnable, ExceptionListener } } + public void setupCorrelationID(String correlationId, int expectedCount) + { + PerCorrelationId perCorrelationId = new PerCorrelationId(); + + // Create a count down latch to count the number of replies with. This is created before the messages are + // sent so that the replies cannot be received before the count down is created. + // One is added to this, so that the last reply becomes a special case. The special case is that the + // chained message listener must be called before this sender can be unblocked, but that decrementing the + // countdown needs to be done before the chained listener can be called. + perCorrelationId.trafficLight = new CountDownLatch(expectedCount + 1); + + perCorrelationIds.put(correlationId, perCorrelationId); + } + + /** * Sends the specified number of ping message and then waits for all correlating replies. If the wait times out * before a reply arrives, then a null reply is returned from this method. This method allows the caller to specify @@ -1122,33 +1149,24 @@ public class PingPongProducer implements Runnable, ExceptionListener public int pingAndWaitForReply(Message message, int numPings, int preFill, long timeout, String messageCorrelationId) throws JMSException, InterruptedException { - - // If we are runnning a consumeOnly test then don't send any messages - - /*log.debug("public int pingAndWaitForReply(Message message, int numPings = " + numPings + ", long timeout = " + timeout + ", String messageCorrelationId = " + messageCorrelationId + "): called");*/ + int totalPingsRequested = numPings + preFill; + // Generate a unique correlation id to put on the messages before sending them, if one was not specified. if (messageCorrelationId == null) { messageCorrelationId = Long.toString(_correlationIdGenerator.incrementAndGet()); + + setupCorrelationID(messageCorrelationId, getExpectedNumPings(totalPingsRequested)); } try { // NDC.push("prod"); - // Create a count down latch to count the number of replies with. This is created before the messages are - // sent so that the replies cannot be received before the count down is created. - // One is added to this, so that the last reply becomes a special case. The special case is that the - // chained message listener must be called before this sender can be unblocked, but that decrementing the - // countdown needs to be done before the chained listener can be called. - PerCorrelationId perCorrelationId = new PerCorrelationId(); - - int totalPingsRequested = numPings + preFill; - perCorrelationId.trafficLight = new CountDownLatch(getExpectedNumPings(totalPingsRequested) + 1); - perCorrelationIds.put(messageCorrelationId, perCorrelationId); + PerCorrelationId perCorrelationId = perCorrelationIds.get(messageCorrelationId); // Set up the current time as the start time for pinging on the correlation id. This is used to determine // timeouts. @@ -1167,9 +1185,9 @@ public class PingPongProducer implements Runnable, ExceptionListener // // Return the number of requested messages, this will let the test // report a pass. - if (_noOfConsumers == 0) + if (_noOfConsumers == 0 || _sendOnly) { - return totalPingsRequested; + return getExpectedNumPings(totalPingsRequested); } do diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java index 9397db82c9..dfb82b9b2d 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java @@ -164,6 +164,14 @@ public class MessageThroughputPerf extends FrameworkBaseCase implements TimingCo threadSetup.set(setup); } + /** + * Called after all threads have completed their setup. + */ + public void postThreadSetUp() + { + //Nothing to do here, potentially implement preFill as per PingTestPerf. + } + /** * Called when a test thread is destroyed. */ -- cgit v1.2.1 From fc324fe97d76c61d0adcc9d2a20dbdc1d17a51cc Mon Sep 17 00:00:00 2001 From: Rajith Muditha Attapattu Date: Wed, 2 Jun 2010 16:14:28 +0000 Subject: QPID-2639 Changed all existing test cases that extened QpidTestCase to QpidBrokerTestCase. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@950617 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java index 728b9d5872..42811e62ef 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java @@ -20,9 +20,9 @@ import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQTopic; import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.test.utils.QpidBrokerTestCase; -public class TopicWithSelectorsTransientVolumeTest extends QpidTestCase +public class TopicWithSelectorsTransientVolumeTest extends QpidBrokerTestCase { private static final int NUM_MSG_PER_ITERATION = 50;//must be a multiple of 10 private static final int NUM_ITERATIONS = 1000; -- cgit v1.2.1 From c1d1a1d8336beb13838c35f37d1e7e7c12ca93cc Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 2 Jun 2010 19:58:39 +0000 Subject: Add the ASF License to various classes currently missing it git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@950740 13f79535-47bb-0310-9956-ffa450edef68 --- .../TopicWithSelectorsTransientVolumeTest.java | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java index 42811e62ef..e0c0b00335 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/TopicWithSelectorsTransientVolumeTest.java @@ -1,3 +1,23 @@ +/* + * + * 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.qpid.topic; import java.util.ArrayList; @@ -321,4 +341,4 @@ public class TopicWithSelectorsTransientVolumeTest extends QpidBrokerTestCase // test.test50SubscribersWith90PercentMatched(); // test.tearDown(); // } -} \ No newline at end of file +} -- cgit v1.2.1 From 8c8130d0288446f88deef393823cccffcaed474d Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Sun, 12 Sep 2010 22:40:40 +0000 Subject: QPID-2857 : Address issues found by running FindBugs against the Java codebase git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@996393 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java | 2 +- .../java/org/apache/qpid/test/testcases/MessageThroughputPerf.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'qpid/java/perftests/src/main/java/org/apache') diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java index 04e723069a..2fe852af77 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java @@ -67,7 +67,7 @@ public class PingSendOnlyClient extends PingDurableClient // pingProducer.getConnection().setExceptionListener(pingProducer); // Run the test procedure. - int sent = pingProducer.send(); + pingProducer.send(); pingProducer.waitForUser("Press return to close connection and quit."); pingProducer.closeConnection(); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java b/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java index dfb82b9b2d..e2e97ab6f8 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/test/testcases/MessageThroughputPerf.java @@ -126,7 +126,7 @@ public class MessageThroughputPerf extends FrameworkBaseCase implements TimingCo { NDC.push(getName()); - testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults); + setTestProps(TestContextProperties.getInstance(MessagingTestConfigProperties.defaults)); } /** @@ -143,7 +143,7 @@ public class MessageThroughputPerf extends FrameworkBaseCase implements TimingCo public void threadSetUp() { // Run the test setup tasks. This may create an in-vm broker, if a decorator has injected a task for this. - taskHandler.runSetupTasks(); + getTaskHandler().runSetupTasks(); // Get the test parameters, any overrides on the command line will have been applied. ParsedProperties testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults); @@ -178,7 +178,7 @@ public class MessageThroughputPerf extends FrameworkBaseCase implements TimingCo public void threadTearDown() { // Run the test teardown tasks. This may destroy the in-vm broker, if a decorator has injected a task for this. - taskHandler.runSetupTasks(); + getTaskHandler().runSetupTasks(); } /** -- cgit v1.2.1