
org.geomajas.project.profiling.service.ProfilingContainer Maven / Gradle / Ivy
The newest version!
/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2013 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the Apache
* License, Version 2.0. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.project.profiling.service;
import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.EventHandler;
import com.lmax.disruptor.MultiThreadedClaimStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.RingBuffer;
import org.geomajas.annotation.Api;
import org.geomajas.project.profiling.jmx.GroupData;
import org.geomajas.project.profiling.jmx.ProfilingBean;
import org.geomajas.project.profiling.jmx.ProfilingData;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Bean for building and reading profiling data.
*
* @author Joachim Van der Auwera
* @since 1.0.0
*/
@Api
public class ProfilingContainer implements ProfilingBean {
private static final OneContainer CLEAR = new OneContainer(0, 0);
private static final GroupDataComparator GROUP_DATA_COMPARATOR = new GroupDataComparator();
private int ringSize = 1024; // must be a power of two
private ExecutorService executorService;
private Disruptor disruptor;
private RingBuffer ringBuffer;
private final Map groupData =
new ConcurrentHashMap();
private OneContainer total = CLEAR;
/**
* Set ring size. Should be done before starting the ProfilingContainer. Otherwise the default value may be used.
*
* @param ringSize ring size
*/
@Api
public void setRingSize(int ringSize) {
this.ringSize = ringSize;
}
/**
* Set up the disruptor service to have a single consumer which aggregates the data.
*/
@PostConstruct
public void start() {
executorService = Executors.newCachedThreadPool();
disruptor = new Disruptor(Registration.FACTORY,
executorService,
new MultiThreadedClaimStrategy(ringSize),
new BlockingWaitStrategy());
disruptor.handleEventsWith(new ContainerEventHandler());
ringBuffer = disruptor.start();
}
/**
* Stop processing incoming data.
*/
@PreDestroy
public void shutdown() {
disruptor.shutdown();
executorService.shutdownNow();
}
/** {@inheritDoc} */
@Api
public void clear() {
register("", -1);
}
/**
* Add a registration for a group.
*
* @param group group name
* @param duration duration
*/
@Api
public void register(String group, long duration) {
if (null == group) {
group = "";
}
final long sequence = ringBuffer.next();
final Registration registration = ringBuffer.get(sequence);
registration.setGroup(group);
registration.setDuration(duration);
ringBuffer.publish(sequence);
}
/** {@inheritDoc} */
@Api
public List getGroupData() {
List result = new ArrayList();
boolean done = false;
while (!done) {
try {
for (Map.Entry entry : groupData.entrySet()) {
OneContainer gv = entry.getValue().getValue();
GroupData gd = new GroupContainer(entry.getKey(), gv.getInvocationCount(), gv.getTotalRunTime());
result.add(gd);
}
done = true;
} catch (ConcurrentModificationException cme) {
result.clear();
}
}
Collections.sort(result, GROUP_DATA_COMPARATOR);
return result;
}
/** {@inheritDoc} */
@Api
public ProfilingData getTotal() {
return total;
}
/**
* Handler which reads the Registration messages and merges in the current profiling data.
*/
private class ContainerEventHandler implements EventHandler {
public void onEvent(final Registration registration, final long sequence, final boolean endOfBatch)
throws Exception {
String group = registration.getGroup();
long duration = registration.getDuration();
if (duration < 0) {
// clear data
groupData.clear();
total = CLEAR;
} else {
total = new OneContainer(total.getInvocationCount() + 1, total.getTotalRunTime() + duration);
OneContainerContainer container = groupData.get(group);
if (null == container) {
container = new OneContainerContainer();
container.setValue(new OneContainer(1, duration));
groupData.put(group, container);
} else {
OneContainer gd = container.getValue();
container.setValue(new OneContainer(gd.getInvocationCount() + 1, gd.getTotalRunTime() + duration));
}
}
}
}
/**
* Comparator for {@link GroupData} instances.
*/
private static class GroupDataComparator implements Comparator {
public int compare(GroupData left, GroupData right) {
return left.getGroup().compareTo(right.getGroup());
}
}
/**
* Container which contains a {@link OneContainer}.
*/
private static class OneContainerContainer {
private OneContainer value;
/**
* Get contained OneContainer.
*
* @return oneContainer
*/
public OneContainer getValue() {
return value;
}
/**
* Set contained OneContainer.
*
* @param value oneContainer
*/
public void setValue(OneContainer value) {
this.value = value;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy