Java tutorial
/*(C) 2007-2012 Alibaba Group Holding Limited. *This program is free software; you can redistribute it and/or modify *it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * Authors: * junyu <junyu@taobao.com> , shenxun <shenxun@taobao.com>, * linxuan <linxuan@taobao.com> ,qihao <qihao@taobao.com> */ package com.taobao.tddl.common.util; import java.util.Arrays; import java.util.Map; import java.util.Properties; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.taobao.tddl.common.ConfigServerHelper; /** * * * * 12(batchLimits) * timeDelay * * * limit1/n * * @author linxuan * */ public class SmoothValve { private static final Log log = LogFactory.getLog(SmoothValve.class); private volatile boolean available = true; private volatile boolean isInSmooth = false; // private final AtomicInteger count = new AtomicInteger(); private final AtomicInteger batchNo = new AtomicInteger(); private final int[] batchLimits; private final AtomicInteger rejectCount = new AtomicInteger(); private final long timeDelay; //ms private volatile long timeBegin; public SmoothValve(long timeDelay) { this.timeDelay = timeDelay; this.batchLimits = new int[] { 1, 2, 4, 8, 16, 32, 64 }; } /** * @param timeDelay * @param batchLimits limitclietclient * -10 * -2client1/2(1/2) * -3client1/3(1/3) * ... * batchLimits = new int[] { -4,-3,-2, 1, 2, 4, 8, 16, 32 }; */ public SmoothValve(long timeDelay, int[] batchLimits) { this.timeDelay = timeDelay; this.batchLimits = batchLimits; } private volatile boolean hasRejectInLastBatch = false; /** * @return * true: false */ public boolean smoothThroughOnInitial() { if (timeDelay == 0) { // return true; } while (isInSmooth && available) { // int batch = batchNo.get(); if (batch >= batchLimits.length) { if (hasRejectInLastBatch) { //rejectbatchLimit batchNo.set(batchLimits.length - 1); hasRejectInLastBatch = false; continue; } isInSmooth = false; count.set(0); batchNo.set(0); rejectCount.set(0); return available; // } hasRejectInLastBatch = false; int limit = batchLimits[batch]; if (limit < -1) { //0-1 int randomInt = new Random().nextInt(-limit); if (randomInt == 0) { return available; // } else { logReject(rejectCount, limit); return false; // } } int current = count.get(); while (current < limit) { if (count.compareAndSet(current, current + 1)) { timeBegin = System.currentTimeMillis(); return available; // } current = count.get(); } //current >= limit if (System.currentTimeMillis() - timeBegin > timeDelay) { //timeDelay * (batch + 1) // batchNo.compareAndSet(batch, batch + 1); // } else { logReject(rejectCount, limit); return false; // } } return available; } private void logReject(AtomicInteger rejectCount, int limit) { hasRejectInLastBatch = true; int rc = rejectCount.incrementAndGet(); log.warn("A request reject in available switch. limit=" + limit + ",rejectCount=" + rc); } /** * @return */ public boolean isAvailable() { return available; } public boolean isNotAvailable() { return !available; } /** * */ public void setAvailable() { if (available) { return; } count.set(0); batchNo.set(0); this.isInSmooth = true; this.available = true; } /** * */ public void setNotAvailable() { if (available) { rejectCount.set(0); this.available = false; } } private static enum CreateProperties { timeDelay, batchLimits; } public static SmoothValve parse(String str) { Properties p = ConfigServerHelper.parseProperties(str, "[SmoothValve Properties]"); if (p == null) { log.warn("Empty tddlconfig"); return null; } try { long td = 0; String[] limits = null; for (Map.Entry<Object, Object> entry : p.entrySet()) { String key = ((String) entry.getKey()).trim(); String value = ((String) entry.getValue()).trim(); switch (CreateProperties.valueOf(key)) { case timeDelay: td = Integer.parseInt(value); break; case batchLimits: limits = value.split("\\|"); break; default: break; } } if (td == 0) { log.error("SmoothValve Properties incomplete"); return null; } if (limits != null) { int[] limitArray = new int[limits.length]; for (int i = 0; i < limits.length; i++) { limitArray[i] = Integer.parseInt(limits[i].trim()); } return new SmoothValve(td, limitArray); } else { return new SmoothValve(td); } } catch (Exception e) { log.error("parse SmoothValve Properties failed", e); return null; } } @Override public String toString() { return new StringBuilder("timeDelay=").append(timeDelay).append(",batchLimits=") .append(Arrays.toString(batchLimits)).toString(); } }