com.taobao.tddl.interact.rule.VirtualTable.java Source code

Java tutorial

Introduction

Here is the source code for com.taobao.tddl.interact.rule.VirtualTable.java

Source

/*(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.interact.rule;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.taobao.tddl.interact.rule.bean.AdvancedParameter;
import com.taobao.tddl.interact.rule.bean.DBType;
import com.taobao.tddl.interact.rule.ruleimpl.EnumerativeRule;
import com.taobao.tddl.interact.rule.virtualnode.DBTableMap;
import com.taobao.tddl.interact.rule.virtualnode.TableSlotMap;

/**
 * 
 * 
 * @author linxuan
 * 
 */
public class VirtualTable implements VirtualTableRule<String, String> {
    private static Log logger = LogFactory.getLog(VirtualTable.class);

    protected String virtualTbName;
    private Map<String, Set<String>> actualTopology;
    //private String[] dbIndexes; //

    protected String dbNamePattern; //item_{0000}_dbkey
    protected String tbNamePattern; //item_{0000}

    protected List<Rule<String>> dbShardRules;
    protected List<Rule<String>> tbShardRules;

    //add by junyu:package
    protected static String extraPackagesStr;

    private Object outerContext;

    private DBType dbType = null; //Oracle|MySql
    private boolean allowReverseOutput; //
    private boolean allowFullTableScan; //
    private boolean disableFullTableScan = true; // 

    /**
     * 
     */
    protected TableSlotMap tableSlotMap;
    protected DBTableMap dbTableMap;
    protected String tableSlotKeyFormat;

    /**
     * TDataSourcetrue
     */
    private boolean needRowCopy = false;

    /**
     * TDataSource
     * 
     * List 
     * ListSet
     * 
     * SQLlistsql
     */
    private List<String> uniqueKeys;

    public void init() {
        if (tbShardRules == null || tbShardRules.size() == 0) {
            if (this.tbNamePattern == null) {
                //tbKeyPattern
                this.tbNamePattern = this.virtualTbName;
            }
        }

        initActualTopology();
    }

    protected void initVnodeMap() {
        if (tableSlotMap != null) {
            tableSlotMap.setTableSlotKeyFormat(tableSlotKeyFormat);
            tableSlotMap.setLogicTable(this.virtualTbName);
            tableSlotMap.init();
        }

        if (dbTableMap != null) {
            dbTableMap.setTableSlotKeyFormat(tableSlotKeyFormat);
            dbTableMap.setLogicTable(this.virtualTbName);
            dbTableMap.init();
        }
    }

    private static final String tableNameSepInSpring = ",";

    public void initActualTopology() {
        if (actualTopology != null) {
            //Set
            for (Map.Entry<String/**/, Set<String/**/>> e : this.actualTopology.entrySet()) {
                if (e.getValue().size() == 1) { //
                    Set<String> tables = new LinkedHashSet<String>();
                    tables.addAll(Arrays.asList(e.getValue().iterator().next().split(tableNameSepInSpring)));
                    e.setValue(tables);
                }
            }
            showTopology(false);
            return; //
        }
        actualTopology = new TreeMap<String, Set<String>>();

        if ((dbShardRules == null || dbShardRules.size() == 0)
                && (tbShardRules == null || tbShardRules.size() == 0)) {
            Set<String> tbs = new TreeSet<String>();
            tbs.add(this.tbNamePattern);
            actualTopology.put(this.dbNamePattern, tbs);
        } else if (dbShardRules == null || dbShardRules.size() == 0) { //
            Set<String> tbs = new TreeSet<String>();
            for (Rule<String> tbRule : tbShardRules) {
                tbs.addAll(vbvRule(tbRule, getEnumerates(tbRule)));
            }
            actualTopology.put(this.dbNamePattern, tbs);
        } else if (tbShardRules == null || tbShardRules.size() == 0) {//
            Set<String> tbs = new TreeSet<String>();
            tbs.add(this.tbNamePattern);
            for (Rule<String> dbRule : dbShardRules) {
                for (String dbIndex : vbvRule(dbRule, getEnumerates(dbRule))) {
                    actualTopology.put(dbIndex, tbs);
                }
            }
        } else { //
            for (Rule<String> dbRule : dbShardRules) {
                for (Rule<String> tbRule : tbShardRules) {
                    if (this.tableSlotMap != null && this.dbTableMap != null) {
                        valuebyvalue(this.actualTopology, dbRule, tbRule, true);
                    } else {
                        valuebyvalue(this.actualTopology, dbRule, tbRule, false);
                    }
                }
            }
        }
        showTopology(true);
    }

    private static Set<String> vbvRule(Rule<String> rule, Samples samples) {
        Set<String> tbs = new TreeSet<String>();
        for (Map<String, Object> sample : samples) {
            tbs.add(rule.eval(sample, null));
        }
        return tbs;
    }

    private Set<String> vbvRule(Rule<String> rule, Map<String, Set<Object>> enumerates) {
        Set<String> tbs = new TreeSet<String>();
        for (Map<String, Object> sample : new Samples(enumerates)) {
            tbs.add(rule.eval(sample, null));
        }
        return tbs;
    }

    private static Map<String, Samples> vbvTrace(Rule<String> rule, Map<String, Set<Object>> enumerates) {
        Map<String, Samples> db2Samples = new TreeMap<String, Samples>();
        Samples dbSamples = new Samples(enumerates);
        for (Map<String, Object> sample : dbSamples) {
            String v = rule.eval(sample, null);
            Samples s = db2Samples.get(v);
            if (s == null) {
                s = new Samples(sample.keySet());
                db2Samples.put(v, s);
            }
            s.addSample(sample);
        }
        return db2Samples;
    }

    private static void valuebyvalue(Map<String, Set<String>> topology, Rule<String> dbRule, Rule<String> tbRule,
            boolean isVnode) {
        Map<String/**/, Set<Object>> dbEnumerates = getEnumerates(dbRule);
        Map<String/**/, Set<Object>> tbEnumerates = getEnumerates(tbRule);
        //Samples dbSamples = new Samples(dbEnumerates);
        //Samples tbSamples = new Samples(tbEnumerates);

        Set<AdvancedParameter> params = cast(tbRule.getRuleColumnSet());
        for (AdvancedParameter tbap : params) {
            if (dbEnumerates.containsKey(tbap.key)) {
                //= =!
                Set<Object> tbValuesBasedONdbValue = new HashSet<Object>();
                for (Object dbValue : dbEnumerates.get(tbap.key)) {
                    tbValuesBasedONdbValue.addAll(tbap.enumerateRange(dbValue));
                }
                dbEnumerates.get(tbap.key).addAll(tbValuesBasedONdbValue);
            } else {
                dbEnumerates.put(tbap.key, tbEnumerates.get(tbap.key));
            }
        }

        //
        if (isVnode) {
            Samples tabSamples = new Samples(tbEnumerates);
            Set<String> tbs = new TreeSet<String>();
            for (Map<String, Object> sample : tabSamples) {
                String value = tbRule.eval(sample, null);
                tbs.add(value);
            }

            for (String table : tbs) {
                Map<String, Object> sample = new HashMap<String, Object>(1);
                sample.put(EnumerativeRule.REAL_TABLE_NAME_KEY, table);
                String db = dbRule.eval(sample, null);
                if (topology.get(db) == null) {
                    Set<String> tabs = new HashSet<String>();
                    tabs.add(table);
                    topology.put(db, tabs);
                } else {
                    topology.get(db).add(table);
                }
            }

            return;
        }

        //
        Map<String, Samples> dbs = vbvTrace(dbRule, dbEnumerates);//
        for (Map.Entry<String/**/, Samples> e : dbs.entrySet()) {
            Set<String> tbs = topology.get(e.getKey());
            if (tbs == null) {
                tbs = vbvRule(tbRule, e.getValue());
                topology.put(e.getKey(), tbs);
            } else {
                tbs.addAll(vbvRule(tbRule, e.getValue()));
            }
        }
    }

    /**
     * #id,1,32|512_64#
     */
    @SuppressWarnings("rawtypes")
    private static Map<String/**/, Set<Object>/**/> getEnumerates(Rule rule) {
        Set<AdvancedParameter> params = cast(rule.getRuleColumnSet());
        Map<String/**/, Set<Object>/**/> enumerates = new HashMap<String, Set<Object>>(params.size());
        for (AdvancedParameter ap : params) {
            enumerates.put(ap.key, ap.enumerateRange());
        }
        return enumerates;
    }

    private static final int showColsPerRow = 5;

    private void showTopology(boolean showMap) {
        int crossIndex, endIndex, maxcolsPerRow = showColsPerRow, maxtbnlen = 1, maxdbnlen = 1;
        for (Map.Entry<String, Set<String>> e : this.actualTopology.entrySet()) {
            int colsPerRow = colsPerRow(e.getValue(), showColsPerRow);
            if (colsPerRow > maxcolsPerRow) {
                maxcolsPerRow = colsPerRow;
            }
            if (e.getKey().length() > maxdbnlen) {
                maxdbnlen = e.getKey().length(); //dbIndex
            }
            for (String tbn : e.getValue()) {
                if (tbn.length() > maxtbnlen) {
                    maxtbnlen = tbn.length(); //tableName
                }
            }
        }
        crossIndex = maxdbnlen + 1;
        endIndex = crossIndex + (maxtbnlen + 1) * maxcolsPerRow + 1;
        StringBuilder sb = new StringBuilder("The topology of the virtual table " + this.virtualTbName);
        addLine(sb, crossIndex, endIndex);
        for (Map.Entry<String/**/, Set<String/**/>> e : this.actualTopology.entrySet()) {
            sb.append("\n|");
            sb.append(fillAfter(e.getKey(), maxdbnlen)).append("|");
            int i = 0, n = e.getValue().size();
            for (String tb : e.getValue()) {
                sb.append(fillAfter(tb, maxtbnlen)).append(",");
                i++;
                if (i % maxcolsPerRow == 0 && i < n) {
                    sb.append("|\n|").append(fillAfter(" ", maxdbnlen)).append("|");//
                }
            }
            if (i % maxcolsPerRow != 0) {
                int taillen = (maxcolsPerRow - (i % maxcolsPerRow)) * (maxtbnlen + 1) + 1;
                sb.append(fillBefore("|", taillen));
            } else {
                sb.append("|");
            }

            addLine(sb, crossIndex, endIndex);
        }
        sb.append("\n");
        logger.warn(sb);

        if (!showMap) {
            return;
        }
        sb = new StringBuilder("\nYou could add below segement as the actualTopology property to ");
        sb.append(this.virtualTbName + "'s TableRule bean in the rule file\n\n");
        sb.append("        <property name=\"actualTopology\">\n");
        sb.append("          <map>\n");
        for (Map.Entry<String/**/, Set<String/**/>> e : this.actualTopology.entrySet()) {
            sb.append("            <entry key=\"").append(e.getKey()).append("\" value=\"");
            for (String table : e.getValue()) {
                sb.append(table).append(tableNameSepInSpring);
            }
            if (sb.charAt(sb.length() - 1) == tableNameSepInSpring.charAt(0)) {
                sb.deleteCharAt(sb.length() - 1);
            }
            sb.append("\" />\n");
        }
        sb.append("          </map>\n");
        sb.append("        </property>\n");
        logger.warn(sb);
    }

    private int colsPerRow(Collection<String> c, int maxColPerRow) {
        int n = c.size();
        if (n <= maxColPerRow) {
            return n;
        }
        int maxfiti = maxColPerRow; //i
        int minblank = maxColPerRow; //
        for (int i = maxColPerRow; i > 0; i--) {
            int mod = n % i;
            if (mod == 0) {
                if (n / i <= i) {
                    return i; //
                } else {
                    break;
                }
            } else {
                if (i - mod < minblank) {
                    minblank = i - mod;
                    maxfiti = i;
                }
            }
        }

        return maxfiti;
    }

    private String fillAfter(String str, int len) {
        if (str.length() < len) {
            for (int i = 0, n = len - str.length(); i < n; i++) {
                str = str + " ";
            }
        }
        return str;
    }

    private String fillBefore(String str, int len) {
        if (str.length() < len) {
            for (int i = 0, n = len - str.length(); i < n; i++) {
                str = " " + str;
            }
        }
        return str;
    }

    private void addLine(StringBuilder sb, int crossIndex, int endIndex) {
        sb.append("\n+");
        for (int i = 1; i <= endIndex; i++) {
            if (i == crossIndex || i == endIndex) {
                sb.append("+");
            } else {
                sb.append("-");
            }
        }
    }

    /*
    @Override
    public String mapDbKey(String value) {
       return mapValue(dbKeyPrefix, dbKeySuffix, dbKeyAlignLen, value);
    }
        
    @Override
    public String mapTbKey(String value) {
       return mapValue(tbKeyPrefix, tbKeySuffix, tbKeyAlignLen, value);
    }
    */

    public VirtualTable clone() throws CloneNotSupportedException {
        return (VirtualTable) super.clone();
    }

    @SuppressWarnings("unchecked")
    private static <T> T cast(Object obj) {
        return (T) obj;
    }

    /**
     * getter/setter
     */
    public void setDbNamePattern(String dbKeyPattern) {
        this.dbNamePattern = dbKeyPattern;
    }

    public String getTbNamePattern() {
        return tbNamePattern;
    }

    public void setTbNamePattern(String tbKeyPattern) {
        this.tbNamePattern = tbKeyPattern;
    }

    public List<Rule<String>> getDbShardRules() {
        return dbShardRules;
    }

    public void setDbShardRules(List<Rule<String>> dbShardRules) {
        this.dbShardRules = dbShardRules;
    }

    public List<Rule<String>> getTbShardRules() {
        return tbShardRules;
    }

    public void setTbShardRules(List<Rule<String>> tbShardRules) {
        this.tbShardRules = tbShardRules;
    }

    public DBType getDbType() {
        return dbType;
    }

    public void setDbType(DBType dbType) {
        this.dbType = dbType;
    }

    public boolean isAllowReverseOutput() {
        return allowReverseOutput;
    }

    public void setAllowReverseOutput(boolean allowReverseOutput) {
        this.allowReverseOutput = allowReverseOutput;
    }

    public boolean isDisableFullTableScan() {
        return disableFullTableScan;
    }

    public void setDisableFullTableScan(boolean disableFullTableScan) {
        this.disableFullTableScan = disableFullTableScan;
    }

    public boolean isNeedRowCopy() {
        return needRowCopy;
    }

    public void setNeedRowCopy(boolean needRowCopy) {
        this.needRowCopy = needRowCopy;
    }

    public List<String> getUniqueKeys() {
        return uniqueKeys;
    }

    public void setUniqueKeys(List<String> uniqueKeys) {
        this.uniqueKeys = uniqueKeys;
    }

    public boolean isAllowFullTableScan() {
        return allowFullTableScan;
    }

    public void setAllowFullTableScan(boolean allowFullTableScan) {
        this.allowFullTableScan = allowFullTableScan;
    }

    public Map<String, Set<String>> getActualTopology() {
        return actualTopology;
    }

    public void setActualTopology(Map<String, Set<String>> actualTopology) {
        this.actualTopology = actualTopology;
    }

    public String getVirtualTbName() {
        return virtualTbName;
    }

    public void setVirtualTbName(String virtualTbName) {
        this.virtualTbName = virtualTbName;
    }

    public void setExtraPackagesStr(List<String> extraPackages) {
        StringBuilder ep = new StringBuilder("");
        if (extraPackages != null) {
            int packNum = extraPackages.size();
            for (int i = 0; i < packNum; i++) {
                ep.append("import ");
                ep.append(extraPackages.get(i));
                ep.append(";");
            }
        }
        extraPackagesStr = ep.toString();
    }

    /*public String getVirtualDbName() {
       return virtualDbName;
    }
        
    public void setVirtualDbName(String virtualDbName) {
       this.virtualDbName = virtualDbName;
    }*/

    public Object getOuterContext() {
        return outerContext;
    }

    public void setOuterContext(Map<Object, Object> outerContext) {
        this.outerContext = outerContext;
    }

    public void setTableSlotMap(TableSlotMap tableSlotMap) {
        this.tableSlotMap = tableSlotMap;
    }

    public void setDbTableMap(DBTableMap dbTableMap) {
        this.dbTableMap = dbTableMap;
    }

    public TableSlotMap getTableSlotMap() {
        return tableSlotMap;
    }

    public DBTableMap getDbTableMap() {
        return dbTableMap;
    }

    public void setTableSlotKeyFormat(String tableSlotKeyFormat) {
        this.tableSlotKeyFormat = tableSlotKeyFormat;
    }
}