com.fusesource.forge.jmstest.executor.BenchmarkJMSProducerWrapper.java Source code

Java tutorial

Introduction

Here is the source code for com.fusesource.forge.jmstest.executor.BenchmarkJMSProducerWrapper.java

Source

/*
 * Copyright (C) 2009, Progress Software Corporation and/or its
 * subsidiaries or affiliates.  All rights reserved.
 *
 * 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 com.fusesource.forge.jmstest.executor;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.fusesource.forge.jmstest.benchmark.BenchmarkConfigurationException;
import com.fusesource.forge.jmstest.benchmark.BenchmarkPartConfig;
import com.fusesource.forge.jmstest.benchmark.command.ClientType;
import com.fusesource.forge.jmstest.benchmark.command.ProducerFinishedCommand;
import com.fusesource.forge.jmstest.probe.CountingProbe;
import com.fusesource.forge.jmstest.scenario.BenchmarkIteration;

public class BenchmarkJMSProducerWrapper extends AbstractBenchmarkJMSClient implements Runnable {

    private transient Log log;

    private ScheduledThreadPoolExecutor executor;
    private List<BenchmarkProducer> producers;
    private TimeUnit sendingDelayUnit = TimeUnit.MICROSECONDS;
    private long sendingDelay;
    private CountDownLatch benchmarkIterationLatch;
    private CountingProbe probe;
    private Boolean started = false;

    public BenchmarkJMSProducerWrapper(BenchmarkClient container, BenchmarkPartConfig partConfig) {
        super(container, partConfig);
    }

    @Override
    public ClientType getClientType() {
        return ClientType.PRODUCER;
    }

    public CountingProbe getProbe() {
        return probe;
    }

    public void setProbe(CountingProbe probe) {
        this.probe = probe;
    }

    public void start() {
        synchronized (started) {
            if (!started) {
                log().info("ProducerWrapper (" + getClientId() + ") starting.");
                super.start();
                CountingProbe cp = new CountingProbe(getClientId() + "-COUNTER");
                cp.addObserver(getSamplePersistenceAdapter());
                setProbe(cp);
                getProbeRunner().addProbe(cp);
                benchmarkIterationLatch = new CountDownLatch(1);
                new Thread(this, getClientId().toString()).start();
                new Thread(new Runnable() {
                    public void run() {
                        try {
                            benchmarkIterationLatch.await();
                            log().info("ProducerWrapper (" + getClientId() + ") completed.");
                        } catch (InterruptedException e) {
                            log().warn("Benchmark (" + getClientId() + ") interrupted.");
                        }
                    }
                }).start();
            }
        }
    }

    private void runProducers(long rate, long duration) {

        BigDecimal bd = new BigDecimal(1000000).divide(new BigDecimal(rate), BigDecimal.ROUND_HALF_DOWN);
        long delayInMicroSeconds;
        try {
            delayInMicroSeconds = bd.longValueExact();
        } catch (ArithmeticException e) {
            delayInMicroSeconds = bd.longValue();
            log().warn("Publish rate cannot be expressed as a precise microsecond value, rounding to nearest value "
                    + "[actualDelay: " + delayInMicroSeconds + "]");
        }

        int producersNeeded = (int) (rate / getPartConfig().getMaxConsumerRatePerThread());
        if (producersNeeded == 0) {
            producersNeeded++;
        }

        log.debug("Running " + producersNeeded + " producers for " + duration + "s");
        producers = new ArrayList<BenchmarkProducer>(producersNeeded);
        sendingDelay = delayInMicroSeconds * producersNeeded;
        executor = new ScheduledThreadPoolExecutor(producersNeeded);

        for (int i = 0; i < producersNeeded; i++) {
            try {
                BenchmarkProducer producer = new BenchmarkProducer(this);
                producer.start();
                producer.setMessageCounter(getProbe());
                producers.add(producer);
            } catch (Exception e) {
                throw new BenchmarkConfigurationException("Unable to create BenchmarkProducer instance", e);
            }
        }
        for (BenchmarkProducer producer : producers) {
            // TODO should really hold onto these and monitor for failures until the
            // executor is shutdown
            executor.scheduleAtFixedRate(new MessageSender(producer), 0, sendingDelay, sendingDelayUnit);
        }

        final CountDownLatch latch = new CountDownLatch(1);

        new ScheduledThreadPoolExecutor(1).schedule(new Runnable() {
            public void run() {
                try {
                    log.debug("Shutting down producers.");
                    executor.shutdown();
                    for (BenchmarkProducer producer : producers) {
                        try {
                            producer.release();
                        } catch (Exception e) {
                            log().error("Error releasing producer.");
                        }
                    }
                    latch.countDown();
                } catch (Exception e) {
                }
            }
        }, duration, TimeUnit.SECONDS);

        try {
            latch.await();
        } catch (InterruptedException ie) {
            log().warn("Producer run has been interrupted ...");
        }
    }

    /**
     * Iterate through the profile and run the producers.
     */
    public void run() {
        BenchmarkIteration iteration = getIteration(getPartConfig().getProfileName());
        log().debug("BenchmarkIteration [" + getClientId() + "] starting");
        iteration.startIteration();
        while (iteration.needsMoreRuns()) {
            long rate = iteration.nextEffectiveRate();
            long duration = iteration.getCurrentDuration();

            log().info("BenchmarkIteration [" + iteration.getName() + "] stepping to " + rate + " msg/s for "
                    + duration + " s]");

            runProducers(rate, duration);
        }
        getContainer().sendCommand(new ProducerFinishedCommand(this));
        log().debug("BenchmarkIteration [" + getClientId() + "] done");
        release();
    }

    public void release() {
        if (benchmarkIterationLatch != null && benchmarkIterationLatch.getCount() > 0) {
            benchmarkIterationLatch.countDown();
        }
        super.release();
    }

    private class MessageSender implements Runnable {
        private BenchmarkProducer producer;

        private MessageSender(BenchmarkProducer producer) {
            this.producer = producer;
        }

        public void run() {
            producer.sendMessage();
        }
    }

    private Log log() {
        if (log == null) {
            log = LogFactory.getLog(this.getClass());
        }
        return log;
    }
}