/* | |
* 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.CountFilter | |
* @see com.alibaba.dubbo.rpc.filter.ActiveLimitFilter | |
* @see com.alibaba.dubbo.routing.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 | |
*/ | |
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 | |
*/ | |
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(); | |
} | |
} |