| /** |
| * |
| * 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)); |
| } |
| } |
| } |