/* * Copyright (c) 2013 Websquared, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v2.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * swsong - initial API and implementation */ package org.fastcatsearch.server; import org.fastcatsearch.alert.ClusterAlertService; import org.fastcatsearch.cluster.NodeService; import org.fastcatsearch.control.JobService; import org.fastcatsearch.db.DBService; import org.fastcatsearch.env.Environment; import org.fastcatsearch.exception.FastcatSearchException; import org.fastcatsearch.http.HttpRequestService; import org.fastcatsearch.ir.CollectionQueryCountService; import org.fastcatsearch.ir.IRService; import org.fastcatsearch.job.state.TaskStateService; import org.fastcatsearch.management.SystemWatchService; import org.fastcatsearch.notification.NotificationService; import org.fastcatsearch.plugin.PluginService; import org.fastcatsearch.processlogger.ProcessLoggerService; import org.fastcatsearch.service.ServiceManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.concurrent.CountDownLatch; public class CatServer { private ServiceManager serviceManager; public static long startTime; public static CatServer instance; private static Logger logger; private boolean isRunning; private Thread shutdownHook; protected boolean keepAlive; private String serverHome; private static volatile Thread keepAliveThread; private static volatile CountDownLatch keepAliveLatch; private FileLock fileLock; private File lockFile; public static void main(String... args) throws FastcatSearchException { if (args.length < 1) { usage(); return; } CatServer server = new CatServer(args[0]); if (server.load(args)) { server.start(); } } public void setKeepAlive(boolean b) { keepAlive = b; } public boolean isKeepAlive() { return keepAlive; } public boolean isRunning() { return isRunning; } public static CatServer getInstance() { return instance; } public CatServer() { } public CatServer(String serverHome) { this.serverHome = serverHome; } public boolean load() { return load(null); } public boolean load(String[] args) { boolean isConfig = false; // load 파라미터는 없을수도 있다. if (args != null) { for (int i = 0; i < args.length; i++) { if (isConfig) { isConfig = false; } else if (args[i].equals("-config")) { isConfig = true; } else if (args[i].equals("-help")) { usage(); return false; } } } setKeepAlive(true); return true; } protected static void usage() { System.out.println("usage: java " + CatServer.class.getName() + " [ -help -config ]" + " {HomePath}"); } public void start() throws FastcatSearchException { // 초기화 및 서비스시작을 start로 옮김. // 초기화로직이 init에 존재할 경우, 관리도구에서 검색엔진을 재시작할때, init을 호출하지 않으므로, 초기화를 건너뛰게 // 됨. instance = this; if (serverHome == null) { System.err.println("Warning! No argument for \"{HomePath}\"."); usage(); System.exit(1); } File f = new File(serverHome); if (!f.exists()) { System.err.println("Warning! HomePath \"" + serverHome + "\" is not exist!"); usage(); System.exit(1); } if (fileLock == null) { lockFile = new File(serverHome, ".lock"); try { FileChannel channel = new RandomAccessFile(lockFile, "rw").getChannel(); fileLock = channel.tryLock(); } catch (IOException e) { System.err.println("Error! Cannot create lock file \"" + lockFile.getAbsolutePath() + "\"."); System.exit(1); } if (fileLock == null) { System.err.println("Error! Another instance of CatServer is running at home path = " + serverHome); System.exit(1); } } Environment environment = new Environment(serverHome).init(); logger = LoggerFactory.getLogger(CatServer.class); logger.info("File lock > {}", lockFile.getAbsolutePath()); this.serviceManager = new ServiceManager(environment); serviceManager.asSingleton(); PluginService pluginService = serviceManager.createService("plugin", PluginService.class); DBService dbService = serviceManager.createService("db", DBService.class); dbService.asSingleton(); JobService jobService = serviceManager.createService("job", JobService.class); jobService.asSingleton(); IRService irService = serviceManager.createService("ir", IRService.class); irService.setAnalyzerFactoryManager(pluginService); SystemWatchService systemInfoService = serviceManager.createService("system", SystemWatchService.class); NodeService nodeService = serviceManager.createService("node", NodeService.class); HttpRequestService httpRequestService = serviceManager.createService("http", HttpRequestService.class); NotificationService notificationService = serviceManager.createService("notification", NotificationService.class); ClusterAlertService clusterAlertService = serviceManager.createService("alert", ClusterAlertService.class); clusterAlertService.asSingleton(); ProcessLoggerService processLoggerService = serviceManager.createService("processlogger", ProcessLoggerService.class); TaskStateService taskStateService = serviceManager.createService("taskstate", TaskStateService.class); CollectionQueryCountService collectionQueryCountService = serviceManager.createService("query_count", CollectionQueryCountService.class); logger.info("ServerHome = {}", serverHome); try { //모든 작업풀의 기반이므로 제일먼저 시작. jobService.start(); //분산시스템의 기반이므로 두번째로 시작. nodeService.start(); //문제발생시 알림통로이므로 그 다음으로 시작. clusterAlertService.start(); dbService.start(); //notification서비스는 db서비스를 이용하므로 db가 먼저로딩. notificationService.start(); try { pluginService.start(); } catch (FastcatSearchException e) { logger.error("PluginService 시작에 실패했습니다.", e); } systemInfoService.start(); httpRequestService.start(); processLoggerService.start(); taskStateService.start(); irService.start(); collectionQueryCountService.start(); // 서비스가 모두 뜬 상태에서 후속작업. if (environment.isMasterNode() && pluginService.isRunning()) { pluginService.loadAction(); pluginService.loadSchedule(); } // 색인 스케쥴등록. if (environment.isMasterNode() && irService.isRunning()) { irService.reloadAllSchedule(); } } catch (FastcatSearchException e) { logger.error("CatServer 시작에 실패했습니다.", e); } irService.registerLoadBanlancer(nodeService); if (shutdownHook == null) { shutdownHook = new ServerShutdownHook(); Runtime.getRuntime().addShutdownHook(shutdownHook); } startTime = System.currentTimeMillis(); logger.info("CatServer started!"); isRunning = true; if (keepAlive) { setKeepAlive(); } } private void setKeepAlive() { // keepAliveLatch 가 null일때만 실행되면, restart의 경우 이미 keep alive이므로 재실행하지 않는다. if (keepAliveLatch == null) { keepAliveLatch = new CountDownLatch(1); keepAliveThread = new Thread(new Runnable() { @Override public void run() { try { keepAliveLatch.await(); } catch (InterruptedException e) { // bail out } } }, "CatServer[keepAlive]"); keepAliveThread.setDaemon(false); keepAliveThread.start(); } } public void restart() throws FastcatSearchException { logger.info("Restart CatServer!"); stop(); try { Thread.sleep(1000); } catch (InterruptedException ignore) { // Thread가 인터럽트 걸리므로 한번더 시도. try { Thread.sleep(1000); } catch (InterruptedException ignore2) { } } start(); } public void stop() throws FastcatSearchException { serviceManager.stopService(CollectionQueryCountService.class); serviceManager.stopService(TaskStateService.class); serviceManager.stopService(NotificationService.class); serviceManager.stopService(ClusterAlertService.class); serviceManager.stopService(ProcessLoggerService.class); serviceManager.stopService(HttpRequestService.class); serviceManager.stopService(PluginService.class); serviceManager.stopService(NodeService.class); serviceManager.stopService(SystemWatchService.class); serviceManager.stopService(IRService.class); serviceManager.stopService(JobService.class); serviceManager.stopService(DBService.class); logger.info("CatServer shutdown!"); isRunning = false; } public void close() throws FastcatSearchException { serviceManager.closeService(CollectionQueryCountService.class); serviceManager.closeService(TaskStateService.class); serviceManager.closeService(NotificationService.class); serviceManager.closeService(ClusterAlertService.class); serviceManager.closeService(ProcessLoggerService.class); serviceManager.closeService(HttpRequestService.class); serviceManager.closeService(PluginService.class); serviceManager.closeService(NodeService.class); serviceManager.closeService(SystemWatchService.class); serviceManager.closeService(IRService.class); serviceManager.closeService(JobService.class); serviceManager.closeService(DBService.class); if (fileLock != null) { try { fileLock.release(); logger.info("CatServer Lock Release! {}", fileLock); } catch (IOException e) { logger.error("", e); } try { fileLock.channel().close(); } catch (Exception e) { logger.error("", e); } try { lockFile.delete(); logger.info("Remove .lock file >> {}", lockFile.getAbsolutePath()); } catch (Exception e) { logger.error("", e); } } } protected class ServerShutdownHook extends Thread { @Override public void run() { try { logger.info("Server Shutdown Requested!"); CatServer.this.stop(); CatServer.this.close(); if (keepAliveLatch != null) { keepAliveLatch.countDown(); } } catch (Throwable ex) { logger.error("CatServer.shutdownHookFail", ex); } finally { logger.info("Server Shutdown Complete!"); } } } }