blob: 9aa80a06ae95d05db91f64efc9a5448f09c26ae0 [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.bookkeeper.proto;
import java.beans.ConstructorProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Bookie Server Stats
*/
public class BKStats {
private static final Logger LOG = LoggerFactory.getLogger(BKStats.class);
private static BKStats instance = new BKStats();
public static BKStats getInstance() {
return instance;
}
/**
* A read view of stats, also used in CompositeViewData to expose to JMX
*/
public static class OpStatData {
private final long maxLatency, minLatency;
private final double avgLatency;
private final long numSuccessOps, numFailedOps;
private final String latencyHist;
@ConstructorProperties({"maxLatency", "minLatency", "avgLatency",
"numSuccessOps", "numFailedOps", "latencyHist"})
public OpStatData(long maxLatency, long minLatency, double avgLatency,
long numSuccessOps, long numFailedOps, String latencyHist) {
this.maxLatency = maxLatency;
this.minLatency = minLatency == Long.MAX_VALUE ? 0 : minLatency;
this.avgLatency = avgLatency;
this.numSuccessOps = numSuccessOps;
this.numFailedOps = numFailedOps;
this.latencyHist = latencyHist;
}
public long getMaxLatency() {
return maxLatency;
}
public long getMinLatency() {
return minLatency;
}
public double getAvgLatency() {
return avgLatency;
}
public long getNumSuccessOps() {
return numSuccessOps;
}
public long getNumFailedOps() {
return numFailedOps;
}
public String getLatencyHist() {
return latencyHist;
}
}
/**
* Operation Statistics
*/
public static class OpStats {
static final int NUM_BUCKETS = 3*9 + 2;
long maxLatency = 0;
long minLatency = Long.MAX_VALUE;
double totalLatency = 0.0f;
long numSuccessOps = 0;
long numFailedOps = 0;
long[] latencyBuckets = new long[NUM_BUCKETS];
OpStats() {}
/**
* Increment number of failed operations
*/
synchronized public void incrementFailedOps() {
++numFailedOps;
}
/**
* Update Latency
*/
synchronized public void updateLatency(long latency) {
if (latency < 0) {
// less than 0ms . Ideally this should not happen.
// We have seen this latency negative in some cases due to the
// behaviors of JVM. Ignoring the statistics updation for such
// cases.
LOG.warn("Latency time coming negative");
return;
}
totalLatency += latency;
++numSuccessOps;
if (latency < minLatency) {
minLatency = latency;
}
if (latency > maxLatency) {
maxLatency = latency;
}
int bucket;
if (latency <= 100) { // less than 100ms
bucket = (int)(latency / 10);
} else if (latency <= 1000) { // 100ms ~ 1000ms
bucket = 1 * 9 + (int)(latency / 100);
} else if (latency <= 10000) { // 1s ~ 10s
bucket = 2 * 9 + (int)(latency / 1000);
} else { // more than 10s
bucket = 3 * 9 + 1;
}
++latencyBuckets[bucket];
}
public OpStatData toOpStatData() {
double avgLatency = numSuccessOps > 0 ? totalLatency / numSuccessOps : 0.0f;
StringBuilder sb = new StringBuilder();
for (int i=0; i<NUM_BUCKETS; i++) {
sb.append(latencyBuckets[i]);
if (i != NUM_BUCKETS - 1) {
sb.append(',');
}
}
return new OpStatData(maxLatency, minLatency, avgLatency, numSuccessOps, numFailedOps, sb.toString());
}
/**
* Diff with base opstats
*
* @param base
* base opstats
* @return diff opstats
*/
public OpStats diff(OpStats base) {
OpStats diff = new OpStats();
diff.maxLatency = this.maxLatency > base.maxLatency ? this.maxLatency : base.maxLatency;
diff.minLatency = this.minLatency > base.minLatency ? base.minLatency : this.minLatency;
diff.totalLatency = this.totalLatency - base.totalLatency;
diff.numSuccessOps = this.numSuccessOps - base.numSuccessOps;
diff.numFailedOps = this.numFailedOps - base.numFailedOps;
for (int i = 0; i < NUM_BUCKETS; i++) {
diff.latencyBuckets[i] = this.latencyBuckets[i] - base.latencyBuckets[i];
}
return diff;
}
/**
* Copy stats from other OpStats
*
* @param other other op stats
* @return void
*/
public synchronized void copyOf(OpStats other) {
this.maxLatency = other.maxLatency;
this.minLatency = other.minLatency;
this.totalLatency = other.totalLatency;
this.numSuccessOps = other.numSuccessOps;
this.numFailedOps = other.numFailedOps;
System.arraycopy(other.latencyBuckets, 0, this.latencyBuckets, 0, this.latencyBuckets.length);
}
}
public static final int STATS_ADD = 0;
public static final int STATS_READ = 1;
public static final int STATS_UNKNOWN = 2;
// NOTE: if add other stats, increment NUM_STATS
public static final int NUM_STATS = 3;
OpStats[] stats = new OpStats[NUM_STATS];
private BKStats() {
for (int i=0; i<NUM_STATS; i++) {
stats[i] = new OpStats();
}
}
/**
* Stats of operations
*
* @return op stats
*/
public OpStats getOpStats(int type) {
return stats[type];
}
/**
* Set stats of a specified operation
*
* @param type operation type
* @param stat operation stats
*/
public void setOpStats(int type, OpStats stat) {
stats[type] = stat;
}
/**
* Diff with base stats
*
* @param base base stats
* @return diff stats
*/
public BKStats diff(BKStats base) {
BKStats diff = new BKStats();
for (int i=0; i<NUM_STATS; i++) {
diff.setOpStats(i, stats[i].diff(base.getOpStats(i)));
}
return diff;
}
/**
* Copy stats from other stats
*
* @param other other stats
* @return void
*/
public void copyOf(BKStats other) {
for (int i=0; i<NUM_STATS; i++) {
stats[i].copyOf(other.getOpStats(i));
}
}
}