From 32dbd17bf80f2f904ab4d84a8cd817d3b869f139 Mon Sep 17 00:00:00 2001 From: Sebastian Bazley Date: Wed, 14 Dec 2011 11:10:06 +0000 Subject: [PATCH] Added DiskStore remote sample sender git-svn-id: https://svn.apache.org/repos/asf/jmeter/trunk@1214157 13f79535-47bb-0310-9956-ffa450edef68 Former-commit-id: dd98cc1d00a22c4d54bc390d413f01b6e4f450ca --- bin/jmeter.properties | 3 + .../samplers/DiskStoreSampleSender.java | 170 ++++++++++++++++++ .../jmeter/samplers/SampleSenderFactory.java | 4 + xdocs/changes.xml | 1 + xdocs/usermanual/remote-test.xml | 2 + 5 files changed, 180 insertions(+) create mode 100644 src/core/org/apache/jmeter/samplers/DiskStoreSampleSender.java diff --git a/bin/jmeter.properties b/bin/jmeter.properties index 865f359fb7..51e8ce19ce 100644 --- a/bin/jmeter.properties +++ b/bin/jmeter.properties @@ -569,6 +569,9 @@ wmlParser.types=text/vnd.wap.wml # default queue size #asynch.batch.queue.size=100 # +# DiskStore: as for Hold mode, but serialises the samples to disk, rather than saving in memory +#mode=DiskStore + # Note: the mode is currently resolved on the client; # other properties (e.g. time_threshold) are resolved on the server. diff --git a/src/core/org/apache/jmeter/samplers/DiskStoreSampleSender.java b/src/core/org/apache/jmeter/samplers/DiskStoreSampleSender.java new file mode 100644 index 0000000000..9efdf0cd36 --- /dev/null +++ b/src/core/org/apache/jmeter/samplers/DiskStoreSampleSender.java @@ -0,0 +1,170 @@ +/* + * 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.jmeter.samplers; + +import org.apache.log.Logger; +import org.apache.commons.io.IOUtils; +import org.apache.jorphan.logging.LoggingManager; +import org.apache.jorphan.util.JMeterError; + +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.OutputStream; +import java.io.Serializable; +import java.rmi.RemoteException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * Version of HoldSampleSender that stores the samples on disk as a serialised stream. + */ + +public class DiskStoreSampleSender extends AbstractSampleSender implements Serializable { + private static final Logger log = LoggingManager.getLoggerForClass(); + + private static final long serialVersionUID = 252L; + + private final RemoteSampleListener listener; + + private transient volatile ObjectOutputStream oos; + private transient volatile File temporaryFile; + private transient volatile ExecutorService singleExecutor; + + /** + * @deprecated only for use by test code + */ + @Deprecated + public DiskStoreSampleSender(){ + log.warn("Constructor only intended for use in testing"); // $NON-NLS-1$ + listener = null; + } + + DiskStoreSampleSender(RemoteSampleListener listener) { + this.listener = listener; + log.info("Using DiskStoreSampleSender for this test run"); // client log file + } + + /** {@inheritDoc} */ + public void testEnded() { + // Not needed + } + + public void testEnded(String host) { + log.info("Test Ended on " + host); + singleExecutor.submit(new Runnable(){ + public void run() { + try { + oos.close(); // ensure output is flushed + } catch (IOException e) { + log.error("Failed to close data file ", e); + } + }}); + singleExecutor.shutdown(); // finish processing samples + try { + if (!singleExecutor.awaitTermination(3, TimeUnit.SECONDS)) { + log.error("Executor did not terminate in a timely fashion"); + } + } catch (InterruptedException e1) { + log.error("Executor did not terminate in a timely fashion", e1); + } + ObjectInputStream ois = null; + try { + ois = new ObjectInputStream(new FileInputStream(temporaryFile)); + Object obj = null; + while((obj = ois.readObject()) != null) { + if (obj instanceof SampleEvent) { + try { + listener.sampleOccurred((SampleEvent) obj); + } catch (RemoteException err) { + if (err.getCause() instanceof java.net.ConnectException){ + throw new JMeterError("Could not return sample",err); + } + log.error("returning sample", err); + } + } else { + log.error("Unexpected object type found in data file "+obj.getClass().getName()); + } + } + } catch (EOFException err) { + // expected + } catch (IOException err) { + log.error("returning sample", err); + } catch (ClassNotFoundException err) { + log.error("returning sample", err); + } finally { + try { + listener.testEnded(host); + } catch (RemoteException e) { + log.error("returning sample", e); + } + IOUtils.closeQuietly(ois); + temporaryFile.delete(); + } + } + + public void sampleOccurred(final SampleEvent e) { + // sampleOccurred is called from multiple threads; not safe to write from multiple threads. + // also decouples the file IO from sample generation + singleExecutor.submit(new Runnable() { + public void run() { + try { + oos.writeObject(e); + } catch (IOException err) { + log.error("sampleOccurred", err); + } + } + + } + ); + } + + /** + * Processed by the RMI server code; acts as testStarted(). + * @throws ObjectStreamException + */ + // TODO should errors be thrown back through RMI? + private Object readResolve() throws ObjectStreamException{ + log.info("Using DiskStoreSampleSender for this test run"); // server log file + singleExecutor = Executors.newSingleThreadExecutor(); + try { + temporaryFile = File.createTempFile("SerialisedSampleSender", ".ser"); + temporaryFile.deleteOnExit(); + singleExecutor.submit(new Runnable(){ + public void run() { + OutputStream anOutputStream; + try { + anOutputStream = new FileOutputStream(temporaryFile); + oos = new ObjectOutputStream(anOutputStream); + } catch (IOException e) { + log.error("Failed to create output Stream", e); + } + }}); + } catch (IOException e) { + log.error("Failed to create output file", e); + } + return this; + } +} diff --git a/src/core/org/apache/jmeter/samplers/SampleSenderFactory.java b/src/core/org/apache/jmeter/samplers/SampleSenderFactory.java index c79274d279..a16a7fc5cf 100644 --- a/src/core/org/apache/jmeter/samplers/SampleSenderFactory.java +++ b/src/core/org/apache/jmeter/samplers/SampleSenderFactory.java @@ -42,6 +42,8 @@ public class SampleSenderFactory { private static final String MODE_ASYNCH = "Asynch"; // $NON-NLS-1$ + private static final String MODE_DISKSTORE = "DiskStore"; // $NON-NLS-1$ + // Support original property name private static final boolean holdSamples = JMeterUtils.getPropDefault("hold_samples", false); // $NON-NLS-1$ @@ -74,6 +76,8 @@ public class SampleSenderFactory { return new DataStrippingSampleSender(listener); } else if(type.equalsIgnoreCase(MODE_ASYNCH)){ return new AsynchSampleSender(listener); + } else if(type.equalsIgnoreCase(MODE_DISKSTORE)){ + return new DiskStoreSampleSender(listener); } else { // should be a user provided class name SampleSender s = null; diff --git a/xdocs/changes.xml b/xdocs/changes.xml index 5e53a9ae4e..91bd8f7766 100644 --- a/xdocs/changes.xml +++ b/xdocs/changes.xml @@ -233,6 +233,7 @@ Loads any additional properties found in META-INF/resources/org.apache.jmeter.na
  • Bug 52242 - FileEditor does not allow output to be saved in a File
  • Bug 51093 - when loading a selection previously stored by "Save Selection As", show the file name in the blue window bar
  • Bug 50086 - Password fields not Hidden in JMS Publisher, JMS Subscriber, Mail Reader sampler, SMTP sampler and Database Configuration
  • +
  • Added DiskStore remote sample sender: like Hold, but saves samples to disk until end of test.
  • Non-functional changes

    diff --git a/xdocs/usermanual/remote-test.xml b/xdocs/usermanual/remote-test.xml index 7e1c7101c6..f473d833aa 100644 --- a/xdocs/usermanual/remote-test.xml +++ b/xdocs/usermanual/remote-test.xml @@ -226,6 +226,8 @@ There are some JMeter properties that can be set to alter this behaviour.