/* * 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 org.opencloudb; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.AsynchronousChannelGroup; import java.util.Map; import java.util.Properties; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.log4j.Logger; import org.opencloudb.backend.PhysicalDBPool; import org.opencloudb.buffer.BufferPool; import org.opencloudb.cache.CacheService; import org.opencloudb.config.model.SystemConfig; import org.opencloudb.interceptor.SQLInterceptor; import org.opencloudb.net.SocketConnector; import org.opencloudb.route.MyCATSequnceProcessor; import org.opencloudb.route.RouteService; import org.opencloudb.statistic.SQLRecorder; import org.opencloudb.util.NameableExecutor; import org.opencloudb.util.TimeUtil; /** * @author mycat */ public class MycatServer2 { public static final String NAME = "MyCat"; private static final long LOG_WATCH_DELAY = 60000L; private static final long TIME_UPDATE_PERIOD = 20L; private static final MycatServer2 INSTANCE = new MycatServer2(); private static final Logger LOGGER = Logger.getLogger("MycatServer"); private final RouteService routerService; private final CacheService cacheService; private Properties dnIndexProperties; private AsynchronousChannelGroup[] asyncChannelGroups; private volatile int channelIndex = 0; private final MyCATSequnceProcessor sequnceProcessor = new MyCATSequnceProcessor(); private final SQLInterceptor sqlInterceptor; private volatile int nextProcessor; private BufferPool bufferPool; private boolean aio = false; public static final MycatServer2 getInstance() { return INSTANCE; } private final MycatConfig config; private final Timer timer; private final SQLRecorder sqlRecorder; private final AtomicBoolean isOnline; private final long startupTime; //private NIOProcessor[] processors; private SocketConnector connector; private NameableExecutor businessExecutor; public MycatServer2() { this.config = new MycatConfig(); this.timer = new Timer(NAME + "Timer", true); this.sqlRecorder = new SQLRecorder(config.getSystem() .getSqlRecordCount()); this.isOnline = new AtomicBoolean(true); cacheService = new CacheService(); routerService = new RouteService(cacheService); // load datanode active index from properties dnIndexProperties = loadDnIndexProps(); try { sqlInterceptor = (SQLInterceptor) Class.forName( config.getSystem().getSqlInterceptor()).newInstance(); } catch (Exception e) { throw new RuntimeException(e); } this.startupTime = TimeUtil.currentTimeMillis(); } public BufferPool getBufferPool() { return bufferPool; } public MyCATSequnceProcessor getSequnceProcessor() { return sequnceProcessor; } public SQLInterceptor getSqlInterceptor() { return sqlInterceptor; } /** * get next AsynchronousChannel ,first is exclude if multi * AsynchronousChannelGroups * * @return */ public AsynchronousChannelGroup getNextAsyncChannelGroup() { if (asyncChannelGroups.length == 1) { return asyncChannelGroups[0]; } else { int index = (++channelIndex) % asyncChannelGroups.length; if (index == 0) { ++channelIndex; return asyncChannelGroups[1]; } else { return asyncChannelGroups[index]; } } } public MycatConfig getConfig() { return config; } public void beforeStart() { String home = SystemConfig.getHomePath(); Log4jInitializer.configureAndWatch(home + "/conf/log4j.xml", LOG_WATCH_DELAY); } public void startup() throws IOException { SystemConfig system = config.getSystem(); int processorCount = system.getProcessors(); // server startup LOGGER.info("==============================================="); LOGGER.info(NAME + " is ready to startup ..."); String inf = "Startup processors ...,total processors:" + system.getProcessors() + ",aio thread pool size:" + system.getProcessorExecutor() + " \r\n each process allocated socket buffer pool " + " bytes ,buffer chunk size:" + system.getProcessorBufferChunk() + " buffer pool's capacity(buferPool/bufferChunk) is:" + system.getProcessorBufferPool() / system.getProcessorBufferChunk(); LOGGER.info(inf); LOGGER.info("sysconfig params:" + system.toString()); // startup manager // ManagerConnectionFactory mf = new ManagerConnectionFactory(); // ServerConnectionFactory sf = new ServerConnectionFactory(); // SocketAcceptor manager = null; // SocketAcceptor server = null; // aio = (system.getUsingAIO() == 1); // // // startup processors // int threadPoolSize = system.getProcessorExecutor(); // processors = new NIOProcessor[processorCount]; // int processBuferPool = system.getProcessorBufferPool(); // int processBufferChunk = system.getProcessorBufferChunk(); // int socketBufferLocalPercent = system.getProcessorBufferLocalPercent(); // bufferPool = new BufferPool(processBuferPool, processBufferChunk, // socketBufferLocalPercent / processorCount); // businessExecutor = ExecutorUtil.create("BusinessExecutor", // threadPoolSize); // // for (int i = 0; i < processors.length; i++) { // processors[i] = new NIOProcessor("Processor" + i, bufferPool, // businessExecutor); // } // // if (aio) { // LOGGER.info("using aio network handler "); // asyncChannelGroups = new AsynchronousChannelGroup[processorCount]; // // startup connector // connector = new AIOConnector(); // for (int i = 0; i < processors.length; i++) { // asyncChannelGroups[i] = AsynchronousChannelGroup // .withFixedThreadPool(processorCount, // new ThreadFactory() { // private int inx = 1; // // @Override // public Thread newThread(Runnable r) { // Thread th = new Thread(r); // th.setName(BufferPool.LOCAL_BUF_THREAD_PREX // + "AIO" + (inx++)); // LOGGER.info("created new AIO thread " // + th.getName()); // return th; // } // }); // // } // manager = new AIOAcceptor(NAME + "Manager", system.getBindIp(), // system.getManagerPort(), mf, this.asyncChannelGroups[0]); // // // startup server // // server = new AIOAcceptor(NAME + "Server", system.getBindIp(), // system.getServerPort(), sf, this.asyncChannelGroups[0]); // // } else { // LOGGER.info("using nio network handler "); // NIOReactorPool reactorPool = new NIOReactorPool( // BufferPool.LOCAL_BUF_THREAD_PREX + "NIOREACTOR", // processors.length); // connector = new NIOConnector(BufferPool.LOCAL_BUF_THREAD_PREX // + "NIOConnector", reactorPool); // ((NIOConnector) connector).start(); // // manager = new NIOAcceptor(BufferPool.LOCAL_BUF_THREAD_PREX + NAME // + "Manager", system.getBindIp(), system.getManagerPort(), // mf, reactorPool); // // server = new NIOAcceptor(BufferPool.LOCAL_BUF_THREAD_PREX + NAME // + "Server", system.getBindIp(), system.getServerPort(), sf, // reactorPool); // } // // manager start // manager.start(); // LOGGER.info(manager.getName() + " is started and listening on " // + manager.getPort()); // server.start(); // // server started // LOGGER.info(server.getName() + " is started and listening on " // + server.getPort()); // LOGGER.info("==============================================="); // // init datahost // Map<String, PhysicalDBPool> dataHosts = config.getDataHosts(); // LOGGER.info("Initialize dataHost ..."); // for (PhysicalDBPool node : dataHosts.values()) { // String index = dnIndexProperties.getProperty(node.getHostName(), // "0"); // if (!"0".equals(index)) { // LOGGER.info("init datahost: " + node.getHostName() // + " to use datasource index:" + index); // } // node.init(Integer.valueOf(index)); // node.startHeartbeat(); // } // timer.schedule(updateTime(), 0L, TIME_UPDATE_PERIOD); // timer.schedule(processorCheck(), 0L, system.getProcessorCheckPeriod()); // long dataNodeIldeCheckPeriod = system.getDataNodeIdleCheckPeriod(); // timer.schedule(dataNodeConHeartBeatCheck(dataNodeIldeCheckPeriod), 0L, // dataNodeIldeCheckPeriod); // timer.schedule(dataNodeHeartbeat(), 0L, // system.getDataNodeHeartbeatPeriod()); } private Properties loadDnIndexProps() { Properties prop = new Properties(); File file = new File(SystemConfig.getHomePath(), "conf" + File.separator + "dnindex.properties"); if (!file.exists()) { return prop; } FileInputStream filein = null; try { filein = new FileInputStream(file); prop.load(filein); } catch (Exception e) { LOGGER.warn("load DataNodeIndex err:" + e); } finally { if (filein != null) { try { filein.close(); } catch (IOException e) { } } } return prop; } /** * save cur datanode index to properties file * * @param dataNode * @param curIndex */ public synchronized void saveDataHostIndex(String dataHost, int curIndex) { File file = new File(SystemConfig.getHomePath(), "conf" + File.separator + "dnindex.properties"); FileOutputStream fileOut = null; try { String oldIndex = dnIndexProperties.getProperty(dataHost); String newIndex = String.valueOf(curIndex); if (newIndex.equals(oldIndex)) { return; } dnIndexProperties.setProperty(dataHost, newIndex); LOGGER.info("save DataHost index " + dataHost + " cur index " + curIndex); File parent = file.getParentFile(); if (parent != null && !parent.exists()) { parent.mkdirs(); } fileOut = new FileOutputStream(file); dnIndexProperties.store(fileOut, "update"); } catch (Exception e) { LOGGER.warn("saveDataNodeIndex err:", e); } finally { if (fileOut != null) { try { fileOut.close(); } catch (IOException e) { } } } } public RouteService getRouterService() { return routerService; } public CacheService getCacheService() { return cacheService; } public NameableExecutor getBusinessExecutor() { return businessExecutor; } public RouteService getRouterservice() { return routerService; } public SocketConnector getConnector() { return connector; } public SQLRecorder getSqlRecorder() { return sqlRecorder; } public long getStartupTime() { return startupTime; } public boolean isOnline() { return isOnline.get(); } public void offline() { isOnline.set(false); } public void online() { isOnline.set(true); } // 系统时间定时更新任务 private TimerTask updateTime() { return new TimerTask() { @Override public void run() { TimeUtil.update(); } }; } // 处理器定时检查任务 private TimerTask processorCheck() { return new TimerTask() { @Override public void run() { // businessExecutor.execute(new Runnable() { // @Override // public void run() { // try { // for (NIOProcessor p : processors) { // p.checkBackendCons(); // } // } catch (Throwable e) { // LOGGER.warn("checkBackendCons caught err:" + e); // } // // } // }); // nextProcessor().getExecutor().execute(new Runnable() { // @Override // public void run() { // try { // for (NIOProcessor p : processors) { // p.checkFrontCons(); // } // } catch (Throwable e) { // LOGGER.warn("checkFrontCons caught err:" + e); // } // } // }); } }; } // 数据节点定时连接空闲超时检查任务 private TimerTask dataNodeConHeartBeatCheck(final long heartPeriod) { return new TimerTask() { @Override public void run() { businessExecutor.execute(new Runnable() { @Override public void run() { Map<String, PhysicalDBPool> nodes = config .getDataHosts(); for (PhysicalDBPool node : nodes.values()) { node.heartbeatCheck(heartPeriod); } Map<String, PhysicalDBPool> _nodes = config .getBackupDataHosts(); if (_nodes != null) { for (PhysicalDBPool node : _nodes.values()) { node.heartbeatCheck(heartPeriod); } } } }); } }; } // 数据节点定时心跳任务 private TimerTask dataNodeHeartbeat() { return new TimerTask() { @Override public void run() { businessExecutor.execute(new Runnable() { @Override public void run() { Map<String, PhysicalDBPool> nodes = config .getDataHosts(); for (PhysicalDBPool node : nodes.values()) { node.doHeartbeat(); } } }); } }; } public boolean isAIO() { return aio; } }