/* * Copyright 1999-2011 Alibaba Group. * * 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.alibaba.dubbo.rpc; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import com.alibaba.dubbo.common.URL; /** * URL statistics. (API, Cached, ThreadSafe) * * @see com.alibaba.dubbo.rpc.filter.ActiveLimitFilter * @see com.alibaba.dubbo.rpc.filter.ExecuteLimitFilter * @see com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance * @author william.liangf */ public class RpcStatus { private static final ConcurrentMap<String, RpcStatus> SERVICE_STATISTICS = new ConcurrentHashMap<String, RpcStatus>(); private static final ConcurrentMap<String, ConcurrentMap<String, RpcStatus>> METHOD_STATISTICS = new ConcurrentHashMap<String, ConcurrentMap<String, RpcStatus>>(); /** * * @param url * @return status */ public static RpcStatus getStatus(URL url) { String uri = url.toIdentityString(); RpcStatus status = SERVICE_STATISTICS.get(uri); if (status == null) { SERVICE_STATISTICS.putIfAbsent(uri, new RpcStatus()); status = SERVICE_STATISTICS.get(uri); } return status; } /** * * @param url */ public static void removeStatus(URL url) { String uri = url.toIdentityString(); SERVICE_STATISTICS.remove(uri); } /** * * @param url * @param methodName * @return status */ public static RpcStatus getStatus(URL url, String methodName) { String uri = url.toIdentityString(); ConcurrentMap<String, RpcStatus> map = METHOD_STATISTICS.get(uri); if (map == null) { METHOD_STATISTICS.putIfAbsent(uri, new ConcurrentHashMap<String, RpcStatus>()); map = METHOD_STATISTICS.get(uri); } RpcStatus status = map.get(methodName); if (status == null) { map.putIfAbsent(methodName, new RpcStatus()); status = map.get(methodName); } return status; } /** * * @param url */ public static void removeStatus(URL url, String methodName) { String uri = url.toIdentityString(); ConcurrentMap<String, RpcStatus> map = METHOD_STATISTICS.get(uri); if (map != null) { map.remove(methodName); } } /** * * @param url */ public static void beginCount(URL url, String methodName) { beginCount(getStatus(url)); beginCount(getStatus(url, methodName)); } private static void beginCount(RpcStatus status) { status.active.incrementAndGet(); } /** * * @param url * @param elapsed * @param succeeded */ public static void endCount(URL url, String methodName, long elapsed, boolean succeeded) { endCount(getStatus(url), elapsed, succeeded); endCount(getStatus(url, methodName), elapsed, succeeded); } private static void endCount(RpcStatus status, long elapsed, boolean succeeded) { status.active.decrementAndGet(); status.total.incrementAndGet(); status.totalElapsed.addAndGet(elapsed); if (status.maxElapsed.get() < elapsed) { status.maxElapsed.set(elapsed); } if (succeeded) { if (status.succeededMaxElapsed.get() < elapsed) { status.succeededMaxElapsed.set(elapsed); } } else { status.failed.incrementAndGet(); status.failedElapsed.addAndGet(elapsed); if (status.failedMaxElapsed.get() < elapsed) { status.failedMaxElapsed.set(elapsed); } } } private final ConcurrentMap<String, Object> values = new ConcurrentHashMap<String, Object>(); private final AtomicInteger active = new AtomicInteger(); private final AtomicLong total = new AtomicLong(); private final AtomicInteger failed = new AtomicInteger(); private final AtomicLong totalElapsed = new AtomicLong(); private final AtomicLong failedElapsed = new AtomicLong(); private final AtomicLong maxElapsed = new AtomicLong(); private final AtomicLong failedMaxElapsed = new AtomicLong(); private final AtomicLong succeededMaxElapsed = new AtomicLong(); private RpcStatus() {} /** * set value. * * @param key * @param value */ public void set(String key, Object value) { values.put(key, value); } /** * get value. * * @param key * @return value */ public Object get(String key) { return values.get(key); } /** * get active. * * @return active */ public int getActive() { return active.get(); } /** * get total. * * @return total */ public long getTotal() { return total.longValue(); } /** * get total elapsed. * * @return total elapsed */ public long getTotalElapsed() { return totalElapsed.get(); } /** * get average elapsed. * * @return average elapsed */ public long getAverageElapsed() { long total = getTotal(); if (total == 0) { return 0; } return getTotalElapsed() / total; } /** * get max elapsed. * * @return max elapsed */ public long getMaxElapsed() { return maxElapsed.get(); } /** * get failed. * * @return failed */ public int getFailed() { return failed.get(); } /** * get failed elapsed. * * @return failed elapsed */ public long getFailedElapsed() { return failedElapsed.get(); } /** * get failed average elapsed. * * @return failed average elapsed */ public long getFailedAverageElapsed() { long failed = getFailed(); if (failed == 0) { return 0; } return getFailedElapsed() / failed; } /** * get failed max elapsed. * * @return failed max elapsed */ public long getFailedMaxElapsed() { return failedMaxElapsed.get(); } /** * get succeeded. * * @return succeeded */ public long getSucceeded() { return getTotal() - getFailed(); } /** * get succeeded elapsed. * * @return succeeded elapsed */ public long getSucceededElapsed() { return getTotalElapsed() - getFailedElapsed(); } /** * get succeeded average elapsed. * * @return succeeded average elapsed */ public long getSucceededAverageElapsed() { long succeeded = getSucceeded(); if (succeeded == 0) { return 0; } return getSucceededElapsed() / succeeded; } /** * get succeeded max elapsed. * * @return succeeded max elapsed. */ public long getSucceededMaxElapsed() { return succeededMaxElapsed.get(); } /** * Calculate average TPS (Transaction per second). * * @return tps */ public long getAverageTps() { if (getTotalElapsed() >= 1000L) { return getTotal() / (getTotalElapsed() / 1000L); } return getTotal(); } }