All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alibaba.dubbo.rpc.RpcStatus Maven / Gradle / Ivy

The newest version!
/*
 * 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.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import com.alibaba.dubbo.common.URL;

/**
 * URL statistics. (API, Cached, ThreadSafe)
 * 
 * @see net.jahhan.extension.filter.ActiveLimitFilter
 * @see net.jahhan.extension.filter.ExecuteLimitFilter
 * @see com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
 * @author william.liangf
 */
public class RpcStatus {

	private static final ConcurrentMap SERVICE_STATISTICS = new ConcurrentHashMap();

	private static final ConcurrentMap> METHOD_STATISTICS = new ConcurrentHashMap>();

	private final ConcurrentMap values = new ConcurrentHashMap();

	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();

	/**
	 * 用来实现executes属性的并发限制(即控制能使用的线程数) 2017-08-21 yizhenqiang
	 */
	private volatile Semaphore executesLimit;
	private volatile int executesPermits;

	private 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 map = METHOD_STATISTICS.get(uri);
		if (map == null) {
			METHOD_STATISTICS.putIfAbsent(uri, new ConcurrentHashMap());
			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 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);
			}
		}
	}

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

	/**
	 * 获取限制线程数的信号量,信号量的许可数就是executes设置的值 2017-08-21 yizhenqiang
	 * 
	 * @param maxThreadNum
	 *            executes设置的值
	 * @return
	 */
	public Semaphore getSemaphore(int maxThreadNum) {
		if (maxThreadNum <= 0) {
			return null;
		}

		if (executesLimit == null || executesPermits != maxThreadNum) {
			synchronized (this) {
				if (executesLimit == null || executesPermits != maxThreadNum) {
					executesLimit = new Semaphore(maxThreadNum);
					executesPermits = maxThreadNum;
				}
			}
		}

		return executesLimit;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy