blob: b29370a78e2ad96ce9c2d648788dc7f6c6d84d0b [file] [log] [blame]
/*
* 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.sling.engine.impl;
import java.util.concurrent.atomic.AtomicReference;
import javax.management.NotCompliantMBeanException;
import javax.management.StandardMBean;
import org.apache.sling.engine.impl.request.RequestData;
import org.apache.sling.engine.jmx.RequestProcessorMBean;
/**
* This is the implementation of the management interface for the
* RequestProcessor.
*/
class RequestProcessorMBeanImpl extends StandardMBean implements RequestProcessorMBean {
private final AtomicReference<Data> dataRef = new AtomicReference<Data>(new Data());
RequestProcessorMBeanImpl() throws NotCompliantMBeanException {
super(RequestProcessorMBean.class);
}
void addRequestData(final RequestData data) {
// do a non-blocking busy loop and atomically set the new data
// the advantage of this algorithm is that there is no blocking
// involved
//
// there might be some memory churn under high contention, but that
// remains to be seen
for ( ;; ) {
Data oldVal = dataRef.get();
Data newVal = new Data(oldVal, data);
boolean success = dataRef.compareAndSet(oldVal, newVal);
if ( success ) {
break;
}
}
}
public void resetStatistics() {
dataRef.set(new Data());
}
public long getRequestsCount() {
return dataRef.get().n;
}
public long getMinRequestDurationMsec() {
return dataRef.get().durationMsecMin;
}
public long getMaxRequestDurationMsec() {
return dataRef.get().durationMsecMax;
}
public double getStandardDeviationDurationMsec() {
return dataRef.get().standardDeviationDurationMsec;
}
public double getMeanRequestDurationMsec() {
return dataRef.get().meanRequestDurationMsec;
}
public int getMaxPeakRecursionDepth() {
return dataRef.get().peakRecursionDepthMax;
}
public int getMinPeakRecursionDepth() {
return dataRef.get().peakRecursionDepthMin;
}
public double getMeanPeakRecursionDepth() {
return dataRef.get().meanPeakRecursionDepth;
}
public double getStandardDeviationPeakRecursionDepth() {
return dataRef.get().standardDeviationPeakRecursionDepth;
}
public int getMaxServletCallCount() {
return dataRef.get().servletCallCountMax;
}
public int getMinServletCallCount() {
return dataRef.get().servletCallCountMin;
}
public double getMeanServletCallCount() {
return dataRef.get().meanServletCallCount;
}
public double getStandardDeviationServletCallCount() {
return dataRef.get().standardDeviationServletCallCount;
}
/**
* Helper class to atomically hold raw data and compute statistics
*/
private static class Data {
// number of requests
private final long n;
// shortest request
private final long durationMsecMin;
// longest request
private final long durationMsecMax;
// sum of request durations
private final double durationMsecSumX;
// sum of squared request durations
private final double durationMsecSumX2;
private final int servletCallCountMin;
private final int servletCallCountMax;
private final double servletCallCountSumX;
private final double servletCallCountSumX2;
private final int peakRecursionDepthMin;
private final int peakRecursionDepthMax;
private final double peakRecursionDepthSumX;
private final double peakRecursionDepthSumX2;
private final double standardDeviationDurationMsec;
private final double meanRequestDurationMsec;
private final double meanPeakRecursionDepth;
private final double standardDeviationPeakRecursionDepth;
private final double meanServletCallCount;
private final double standardDeviationServletCallCount;
// computed fields
Data() {
n = 0;
durationMsecMin = Long.MAX_VALUE;
durationMsecMax = 0;
durationMsecSumX = 0;
durationMsecSumX2 = 0;
servletCallCountMin = Integer.MAX_VALUE;
servletCallCountMax = 0;
servletCallCountSumX = 0;
servletCallCountSumX2 = 0;
peakRecursionDepthMin = Integer.MAX_VALUE;
peakRecursionDepthMax = 0;
peakRecursionDepthSumX = 0;
peakRecursionDepthSumX2 = 0;
standardDeviationDurationMsec = computeStandardDeviationDurationMsec();
meanRequestDurationMsec = computeMeanRequestDurationMsec();
meanPeakRecursionDepth = computeMeanPeakRecursionDepth();
standardDeviationPeakRecursionDepth = computeStandardDeviationPeakRecursionDepth();
meanServletCallCount = computeMeanServletCallCount();
standardDeviationServletCallCount = computeStandardDeviationServletCallCount();
}
Data(Data other, RequestData data) {
if ( other == null || data == null ) {
throw new IllegalArgumentException("Neither 'other' nor 'data' may be null");
}
final long duration = data.getElapsedTimeMsec();
final int servletCallCount = data.getServletCallCount();
final int peakRecursionDepth = data.getPeakRecusionDepth();
n = other.n + 1;
durationMsecMin = Math.min(duration, other.durationMsecMin);
durationMsecMax = Math.max(duration, other.durationMsecMax);
durationMsecSumX = other.durationMsecSumX + duration;
durationMsecSumX2 = other.durationMsecSumX2 + (duration * duration);
servletCallCountMin = Math.min(servletCallCount, other.servletCallCountMin);
servletCallCountMax = Math.max(servletCallCount, other.servletCallCountMax);
servletCallCountSumX = other.servletCallCountSumX + servletCallCount;
servletCallCountSumX2 = other.servletCallCountSumX2 + (servletCallCount * servletCallCount);
peakRecursionDepthMin = Math.min(peakRecursionDepth , other.peakRecursionDepthMin);
peakRecursionDepthMax = Math.max(peakRecursionDepth , other.peakRecursionDepthMax);
peakRecursionDepthSumX = other.peakRecursionDepthSumX + peakRecursionDepth;
peakRecursionDepthSumX2 = other.peakRecursionDepthSumX2 + (peakRecursionDepth * peakRecursionDepth);
standardDeviationDurationMsec = computeStandardDeviationDurationMsec();
meanRequestDurationMsec = computeMeanRequestDurationMsec();
meanPeakRecursionDepth = computeMeanPeakRecursionDepth();
standardDeviationPeakRecursionDepth = computeStandardDeviationPeakRecursionDepth();
meanServletCallCount = computeMeanServletCallCount();
standardDeviationServletCallCount = computeStandardDeviationServletCallCount();
}
private double computeStandardDeviationDurationMsec() {
if (this.n > 1) {
// algorithm taken from
// http://de.wikipedia.org/wiki/Standardabweichung section
// "Berechnung fuer auflaufende Messwerte"
return Math.sqrt((this.durationMsecSumX2 - this.durationMsecSumX * this.durationMsecSumX / this.n) / (this.n - 1));
}
// single data point has no deviation
return 0;
}
private double computeMeanRequestDurationMsec() {
if (this.n > 0) {
return this.durationMsecSumX / this.n;
} else {
return 0;
}
}
private double computeMeanPeakRecursionDepth() {
if (this.n > 0) {
return this.peakRecursionDepthSumX / this.n;
} else {
return 0;
}
}
private double computeStandardDeviationPeakRecursionDepth() {
if (this.n > 1) {
return Math.sqrt((this.peakRecursionDepthSumX2 - this.peakRecursionDepthSumX * this.peakRecursionDepthSumX / this.n) / (this.n - 1));
}
// single data point has no deviation
return 0;
}
private double computeMeanServletCallCount() {
if (this.n > 0) {
return this.servletCallCountSumX / this.n;
} else {
return 0;
}
}
private double computeStandardDeviationServletCallCount() {
if (this.n > 1) {
return Math.sqrt((this.servletCallCountSumX2 - this.servletCallCountSumX * this.servletCallCountSumX / this.n) / (this.n - 1));
}
// single data point has no deviation
return 0;
}
}
}