/** * Alipay.com Inc. * Copyright (c) 2004-2012 All Rights Reserved. */ package com.alipay.zdal.client.datasource.keyweight; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import org.apache.log4j.Logger; import com.alipay.zdal.common.RuntimeConfigHolder; /** * trade-failover��������ԴȨ�ع���ĺ����� * ��Ҫ���Master/Failover����ԴȨ�صĹ�������Ȩ���������һ��db��š� * @author zhaofeng.wang * @version $Id: TDataSourceKeyWeightRandom.java,v 0.1 2012-5-2 ����10:29:56 zhaofeng.wang Exp $ */ public class ZdalDataSourceKeyWeightRandom { private static final Logger logger = Logger .getLogger(ZdalDataSourceKeyWeightRandom.class); /** * ÿ�����ڵ�����Դ�ĸ����� */ private final int dataSourceNumberInGroup; /** * ���������ԴȨ�أ�����keyΪ����Դ��ʶ��valueΪ��Ӧ��Ȩ�� */ private final Map<String, Integer> cachedWeightConfig = new HashMap<String, Integer>(); /** * ����ʱ���������Ȩ�ص����� */ private final RuntimeConfigHolder<Weight> weightHolder = new RuntimeConfigHolder<Weight>(); /** * ���ֲ������ֻ���ؽ��������޸� */ private static class Weight { public Weight(int[] weights, String[] weightKeys, int[] weightAreaEnds) { this.weightKeys = weightKeys; this.weightValues = weights; this.weightAreaEnds = weightAreaEnds; } /** * ����Դ�ı�ʶ��Ϊweight��key�������߱�֤�����޸���Ԫ�� */ public final String[] weightKeys; /** * ����Դ��Ȩ�أ��������weightKeys�е�ֵһһ��Ӧ�������߱�֤�����޸���Ԫ�� */ public final int[] weightValues; /** * ���������Ȩ������Σ���������key��value��Ӧ�������߱�֤�����޸���Ԫ�� */ public final int[] weightAreaEnds; } /** * ��ʼ��Ȩ�ػ��棬�Լ�����Ȩ������� * @param weightKeys ����Դkey * @param weights ������Դkeyһһ��Ӧ��Ȩ��ֵ */ public ZdalDataSourceKeyWeightRandom(String[] weightKeys, int[] weights) { for (int i = 0; i < weightKeys.length; i++) { this.cachedWeightConfig.put(weightKeys[i], weights[i]); } int[] weightAreaEnds = genAreaEnds(weights); this.dataSourceNumberInGroup = weightKeys.length; weightHolder.set(new Weight(weights, weightKeys, weightAreaEnds)); } public Map<String, Integer> getWeightConfig() { return this.cachedWeightConfig; } /** * ����������ڸ���Ȩ�ز�������� */ private final Random random = new Random(); /** * * ����������Ȩ�� 10 9 8 * ��ôareaEnds���� 10 19 27 * �������0~27֮���һ����������ȥ��areaEnds���Ԫ�رȣ������������С��ijԪ�أ����ʾӦ��ѡ�����Ԫ��,�����ظ�Ԫ�ص��±�š� * * ע�⣺�÷������ܸı������������,����ʵ�ֱ�֤���ܸı�w���κ���������ݣ������̲߳���ȫ * @return int */ public int select() { final Weight w = weightHolder.get(); int[] areaEnds = w.weightAreaEnds; int sum = areaEnds[areaEnds.length - 1]; if (sum == 0) { logger.error("��������ԴȨ��ȫ��Ϊ0��areaEnds: " + intArray2String(areaEnds)); return -1; } int rand = random.nextInt(sum); for (int i = 0; i < areaEnds.length; i++) { if (rand < areaEnds[i]) { return i; } } logger.error("Choose the dataSource in the areaEnds failed, the rand=" + rand + ", areaEnds:" + intArray2String(areaEnds)); return -1; } /** * ����Ȩ������ * * @param weights ����Դ��Ȩ������ * @return Ȩ������ */ private static int[] genAreaEnds(int[] weights) { if (weights == null) { return null; } int[] areaEnds = new int[weights.length]; int sum = 0; for (int i = 0; i < weights.length; i++) { sum += weights[i]; areaEnds[i] = sum; } if (logger.isDebugEnabled()) { logger.debug("generate areaEnds" + intArray2String(areaEnds) + " from weights" + intArray2String(weights)); } if (sum == 0) { logger.warn("generate areaEnds" + intArray2String(areaEnds) + " from weights" + intArray2String(weights)); } return areaEnds; } /** * Ȩ��������־���ת�� * @param inta Ȩ������ * @return ��ʽ�������־�ַ��� */ private static String intArray2String(int[] inta) { if (inta == null) { return "null"; } else if (inta.length == 0) { return "[]"; } StringBuilder sb = new StringBuilder(); sb.append("[").append(inta[0]); for (int i = 1; i < inta.length; i++) { sb.append(", ").append(inta[i]); } sb.append("]"); return sb.toString(); } /** * ��ȡ���е�db�ı�ʶ�ϲ�����ַ��� * * @return db��ʶ�����ַ��� */ public String getAllDbKeys() { StringBuilder sb = new StringBuilder(); final Weight w = weightHolder.get(); sb.append("[").append(w.weightKeys[0]); for (int i = 1; i < w.weightKeys.length; i++) { sb.append(",").append(w.weightKeys[i]); } sb.append("]"); return sb.toString(); } /** * ����Ȩ�������ȡdb����� * @param excludeNums ������db��ŵļ��� * @return db����ţ���һ���������ã���Ҫ��Χ��У�� */ public int getRandomDBIndexByWeight(List<Integer> excludeNums) { final Weight w = weightHolder.get(); int weights[] = w.weightValues; List<Integer> dbIndexes = new ArrayList<Integer>(); for (int i = 0; i < weights.length; i++) { if (weights[i] > 0 && !(excludeNums.contains(i))) { dbIndexes.add(i); } } int size = dbIndexes.size(); if (size <= 0) { throw new IllegalArgumentException("û�п��õ�����Դ�ˣ�Ȩ��ȫ��Ϊ0��"); } int rand = random.nextInt(size); return dbIndexes.get(rand); } /** * ���ݴ����db���кţ��ж�db�Ƿ���� * * @param dbNumber db���к� * @return ��ǰdb�Ƿ���� */ public boolean isDataBaseAvailable(int dbNumber) { final Weight w = weightHolder.get(); int weights[] = w.weightValues; if (weights[dbNumber] > 0) { return true; } return false; } /** * ���ز����õ����ݿ����м��� * * @return */ public List<Integer> getNotAvailableDBIndexes() { final Weight w = weightHolder.get(); int weights[] = w.weightValues; List<Integer> dbIndexes = new ArrayList<Integer>(); for (int i = 0; i < weights.length; i++) { if (weights[i] <= 0) { dbIndexes.add(i); } } return dbIndexes; } /** * ���ؿ��õ����ݿ����м��� * * @return */ public List<Integer> getAvailableDBIndexes() { final Weight w = weightHolder.get(); int weights[] = w.weightValues; List<Integer> dbIndexes = new ArrayList<Integer>(); for (int i = 0; i < weights.length; i++) { if (weights[i] > 0) { dbIndexes.add(i); } } return dbIndexes; } /** * ����db��Ż�ȡdb��key��ʶ * @param number db��� * @return db��ʶ */ public String getDBKeyByNumber(int number) { final Weight w = weightHolder.get(); if (number >= w.weightKeys.length) { throw new IllegalArgumentException("The db number is out of scope, number= " + number + ",the largest is " + w.weightKeys.length); } return w.weightKeys[number]; } public String[] getDBWeightKeys() { final Weight w = weightHolder.get(); return w.weightKeys; } public int[] getDBWeightValues() { final Weight w = weightHolder.get(); return w.weightValues; } /** * ����db��Ż�ȡdb��Ȩ�� * @param number db��� * @return db Ȩ�� */ public int getDBWeightByNumber(int number) { final Weight w = weightHolder.get(); if (number >= w.weightKeys.length) { throw new IllegalArgumentException("The db number is out of scope, number= " + number + ",the largest is " + w.weightKeys.length); } return w.weightValues[number]; } /** * ��ȡ���е�����Դ��ʶ * * @return ����Դ��ʶ�������� */ public String[] getDBKeysArray() { String keys[] = weightHolder.get().weightKeys; return keys; } public int getDataSourceNumberInGroup() { return dataSourceNumberInGroup; } }