package com.taobao.tddl.atom.utils;
import java.util.Arrays;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import com.taobao.tddl.monitor.Monitor;
import com.taobao.tddl.monitor.stat.AbstractStatLogWriter.LogCounter;
/**
* 实现应用连接数限制功能中, 具体某一个槽 (Slot) 的连接数限制。
*
* @author changyuan.lh
*/
public final class ConnRestrictSlot {
private final ConnRestrictEntry entry;
/**
* 直接用 信号量, 跟锁一样都是基于 AbstractQueuedSynchronizer, 性能应该 没有问题, 就是不能动态改
* permits。但是现在的推送机制是直接丢掉旧的 TDataSourceWrapper 换个新的: 旧的连接还到旧的 Slot, 新的申请走新
* 建的 Slot, 所以看来没有动态的必要。
*/
private final Semaphore semaphore;
// changyuan.lh: 并发连接数和阻塞等待的统计对象
private final LogCounter statConnNumber;
private final LogCounter statConnBlocking;
public ConnRestrictSlot(String datasourceKey, String slotKey, ConnRestrictEntry entry){
this.statConnNumber = Monitor.connStat(datasourceKey, slotKey, Monitor.KEY3_CONN_NUMBER);
this.statConnBlocking = Monitor.connStat(datasourceKey, slotKey, Monitor.KEY3_CONN_BLOCKING);
this.semaphore = new Semaphore(entry.limits); // Nofair, 带 Spin 性能好一些
this.entry = entry;
}
/**
* changyuan.lh: 记录统计信息
*/
public void statConnection(final long connMillis) {
statConnNumber.stat(1, semaphore.availablePermits());
statConnBlocking.stat(1, connMillis);
}
public boolean allocateConnection(final int timeoutInMillis) throws InterruptedException {
return semaphore.tryAcquire(timeoutInMillis, TimeUnit.MILLISECONDS);
}
public int getAvailableConnections() {
return semaphore.availablePermits();
}
public int getConnections() {
return entry.limits - semaphore.availablePermits();
}
public int getLimits() {
return entry.limits;
}
public void freeConnection() {
semaphore.release();
}
public String toString() {
return "ConnRestrictSlot: @" + Integer.toHexString(hashCode()) + " " + Arrays.toString(entry.keys) + " "
+ entry.limits;
}
}