io.mycat.server.ServerConnection.java Source code

Java tutorial

Introduction

Here is the source code for io.mycat.server.ServerConnection.java

Source

/*
 * Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software;Designed and Developed mainly by many Chinese 
 * opensource volunteers. you can redistribute it and/or modify it under the 
 * terms of the GNU General Public License version 2 only, as published by the
 * Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * Any questions about this component can be directed to it's project Web address 
 * https://code.google.com/p/opencloudb/.
 *
 */
package io.mycat.server;

import java.io.IOException;
import java.nio.channels.NetworkChannel;

import cn.edu.nwsuaf.service.TableService;
import cn.edu.nwsuaf.service.impl.TableServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.mycat.MycatServer;
import io.mycat.config.ErrorCode;
import io.mycat.config.model.SchemaConfig;
import io.mycat.net.FrontendConnection;
import io.mycat.route.RouteResultset;
import io.mycat.server.handler.MysqlInformationSchemaHandler;
import io.mycat.server.handler.MysqlProcHandler;
import io.mycat.server.parser.ServerParse;
import io.mycat.server.response.Heartbeat;
import io.mycat.server.response.InformationSchemaProfiling;
import io.mycat.server.response.Ping;
import io.mycat.server.util.SchemaUtil;
import io.mycat.util.SplitUtil;
import io.mycat.util.TimeUtil;

/**
 * @author mycat
 */
public class ServerConnection extends FrontendConnection {
    private static final Logger LOGGER = LoggerFactory.getLogger(ServerConnection.class);
    private static final long AUTH_TIMEOUT = 15 * 1000L;

    private volatile int txIsolation;
    private volatile boolean autocommit;
    private volatile boolean txInterrupted;
    private volatile String txInterrputMsg = "";
    private long lastInsertId;
    private NonBlockingSession session;
    /**
     * ?lock tables?lock?
     */
    private volatile boolean isLocked = false;

    public ServerConnection(NetworkChannel channel) throws IOException {
        super(channel);
        this.txInterrupted = false;
        this.autocommit = true;
    }

    @Override
    public boolean isIdleTimeout() {
        if (isAuthenticated) {
            return super.isIdleTimeout();
        } else {
            return TimeUtil.currentTimeMillis() > Math.max(lastWriteTime, lastReadTime) + AUTH_TIMEOUT;
        }
    }

    public int getTxIsolation() {
        return txIsolation;
    }

    public void setTxIsolation(int txIsolation) {
        this.txIsolation = txIsolation;
    }

    public boolean isAutocommit() {
        return autocommit;
    }

    public void setAutocommit(boolean autocommit) {
        this.autocommit = autocommit;
    }

    public long getLastInsertId() {
        return lastInsertId;
    }

    public void setLastInsertId(long lastInsertId) {
        this.lastInsertId = lastInsertId;
    }

    /**
     * ???
     */
    public void setTxInterrupt(String txInterrputMsg) {
        if (!autocommit && !txInterrupted) {
            txInterrupted = true;
            this.txInterrputMsg = txInterrputMsg;
        }
    }

    public boolean isTxInterrupted() {
        return txInterrupted;
    }

    public NonBlockingSession getSession2() {
        return session;
    }

    public void setSession2(NonBlockingSession session2) {
        this.session = session2;
    }

    public boolean isLocked() {
        return isLocked;
    }

    public void setLocked(boolean isLocked) {
        this.isLocked = isLocked;
    }

    @Override
    public void ping() {
        Ping.response(this);
    }

    @Override
    public void heartbeat(byte[] data) {
        Heartbeat.response(this, data);
    }

    public void execute(String sql, int type) {
        //?
        if (this.isClosed()) {
            LOGGER.warn("ignore execute ,server connection is closed " + this);
            return;
        }
        // ?
        if (txInterrupted) {
            writeErrMessage(ErrorCode.ER_YES, "Transaction error, need to rollback." + txInterrputMsg);
            return;
        }

        // ?DB
        String db = this.schema;
        boolean isDefault = true;
        if (db == null) {
            db = SchemaUtil.detectDefaultDb(sql, type);
            if (db == null) {
                writeErrMessage(ErrorCode.ERR_BAD_LOGICDB, "No MyCAT Database selected");
                return;
            }
            isDefault = false;
        }

        // PhpAdmin's, ?MySQL?
        //// TODO: 2016/5/20 ?information_schema
        if (ServerParse.SELECT == type && db.equalsIgnoreCase("information_schema")) {
            MysqlInformationSchemaHandler.handle(sql, this);
            return;
        }

        if (ServerParse.SELECT == type && sql.contains("mysql") && sql.contains("proc")) {

            SchemaUtil.SchemaInfo schemaInfo = SchemaUtil.parseSchema(sql);
            if (schemaInfo != null && "mysql".equalsIgnoreCase(schemaInfo.schema)
                    && "proc".equalsIgnoreCase(schemaInfo.table)) {

                // MySQLWorkbench
                MysqlProcHandler.handle(sql, this);
                return;
            }
        }

        SchemaConfig schema = MycatServer.getInstance().getConfig().getSchemas().get(db);
        if (schema == null) {
            writeErrMessage(ErrorCode.ERR_BAD_LOGICDB, "Unknown MyCAT Database '" + db + "'");
            return;
        }

        //fix navicat   SELECT STATE AS `State`, ROUND(SUM(DURATION),7) AS `Duration`, CONCAT(ROUND(SUM(DURATION)/*100,3), '%') AS `Percentage` FROM INFORMATION_SCHEMA.PROFILING WHERE QUERY_ID= GROUP BY STATE ORDER BY SEQ
        if (ServerParse.SELECT == type && sql.contains(" INFORMATION_SCHEMA.PROFILING ")
                && sql.contains("CONCAT(ROUND(SUM(DURATION)/*100,3)")) {
            InformationSchemaProfiling.response(this);
            return;
        }

        /* ?schema?sqlschema?
         * sql?mysql?
         * sqlSchema??
         */
        if (isDefault && schema.isCheckSQLSchema() && isNormalSql(type)) {
            SchemaUtil.SchemaInfo schemaInfo = SchemaUtil.parseSchema(sql);
            if (schemaInfo != null && schemaInfo.schema != null && !schemaInfo.schema.equals(db)) {
                SchemaConfig schemaConfig = MycatServer.getInstance().getConfig().getSchemas()
                        .get(schemaInfo.schema);
                if (schemaConfig != null)
                    schema = schemaConfig;
            }
        }

        routeEndExecuteSQL(sql, type, schema);

    }

    private boolean isNormalSql(int type) {
        return ServerParse.SELECT == type || ServerParse.INSERT == type || ServerParse.UPDATE == type
                || ServerParse.DELETE == type || ServerParse.DDL == type;
    }

    public RouteResultset routeSQL(String sql, int type) {

        // ?DB
        String db = this.schema;
        if (db == null) {
            writeErrMessage(ErrorCode.ERR_BAD_LOGICDB, "No MyCAT Database selected");
            return null;
        }
        SchemaConfig schema = MycatServer.getInstance().getConfig().getSchemas().get(db);
        if (schema == null) {
            writeErrMessage(ErrorCode.ERR_BAD_LOGICDB, "Unknown MyCAT Database '" + db + "'");
            return null;
        }

        // 
        RouteResultset rrs = null;
        try {
            rrs = MycatServer.getInstance().getRouterservice().route(
                    MycatServer.getInstance().getConfig().getSystem(), schema, type, sql, this.charset, this);

        } catch (Exception e) {
            StringBuilder s = new StringBuilder();
            LOGGER.warn(s.append(this).append(sql).toString() + " err:" + e.toString(), e);
            String msg = e.getMessage();
            writeErrMessage(ErrorCode.ER_PARSE_ERROR, msg == null ? e.getClass().getSimpleName() : msg);
            return null;
        }
        return rrs;
    }

    public void routeEndExecuteSQL(String sql, int type, SchemaConfig schema) {
        // 
        RouteResultset rrs = null;
        try {
            rrs = MycatServer.getInstance().getRouterservice().route(
                    MycatServer.getInstance().getConfig().getSystem(), schema, type, sql, this.charset, this);

        } catch (Exception e) {
            StringBuilder s = new StringBuilder();
            LOGGER.warn(s.append(this).append(sql).toString() + " err:" + e.toString(), e);
            String msg = e.getMessage();
            writeErrMessage(ErrorCode.ER_PARSE_ERROR, msg == null ? e.getClass().getSimpleName() : msg);
            return;
        }
        if (rrs != null) {
            // session
            session.execute(rrs, type);

            String stmt = StringUtils.upperCase(rrs.getStatement());
            if (StringUtils.startsWith(stmt, "DROP")) {
                TableService tableService = new TableServiceImpl();
                String tableName = tableService.getTableName(stmt);
                tableService.deleteTable(tableName, schema.getName());
            }
        }
    }

    /**
     * ??
     */
    public void commit() {
        if (txInterrupted) {
            writeErrMessage(ErrorCode.ER_YES, "Transaction error, need to rollback.");
        } else {
            session.commit();
        }
    }

    /**
     * 
     */
    public void rollback() {
        // ?
        if (txInterrupted) {
            txInterrupted = false;
        }

        // 
        session.rollback();
    }

    /**
     * lock tables?
     * @param sql
     */
    public void lockTable(String sql) {
        // ??lock table?
        if (!autocommit) {
            writeErrMessage(ErrorCode.ER_YES, "can't lock table in transaction!");
            return;
        }
        // ?lock tableunlock table???lock table
        if (isLocked) {
            writeErrMessage(ErrorCode.ER_YES, "can't lock multi-table");
            return;
        }
        RouteResultset rrs = routeSQL(sql, ServerParse.LOCK);
        if (rrs != null) {
            session.lockTable(rrs);
        }
    }

    /**
     * unlock tables?
     * @param sql
     */
    public void unLockTable(String sql) {
        sql = sql.replaceAll("\n", " ").replaceAll("\t", " ");
        String[] words = SplitUtil.split(sql, ' ', true);
        if (words.length == 2 && ("table".equalsIgnoreCase(words[1]) || "tables".equalsIgnoreCase(words[1]))) {
            isLocked = false;
            session.unLockTable(sql);
        } else {
            writeErrMessage(ErrorCode.ER_UNKNOWN_COM_ERROR, "Unknown command");
        }

    }

    /**
     * ?
     * 
     * @param sponsor
     *            ?null
     */
    public void cancel(final FrontendConnection sponsor) {
        processor.getExecutor().execute(new Runnable() {
            @Override
            public void run() {
                session.cancel(sponsor);
            }
        });
    }

    @Override
    public void close(String reason) {
        super.close(reason);
        session.terminate();
        if (getLoadDataInfileHandler() != null) {
            getLoadDataInfileHandler().clear();
        }
    }

    @Override
    public String toString() {
        return "ServerConnection [id=" + id + ", schema=" + schema + ", host=" + host + ", user=" + user
                + ",txIsolation=" + txIsolation + ", autocommit=" + autocommit + ", schema=" + schema + "]";
    }

}