From ce5e583b4b2d9fb64af55c9416e5ef1d412e742c Mon Sep 17 00:00:00 2001 From: Jonathan Ellis Date: Tue, 31 Mar 2009 22:17:20 +0000 Subject: [PATCH] Move startup code into CassandraDaemon. Drop stdout and stderr. Add hooks for jsvc, which allows more thorough daemonization (such as dropping priviledges and setting process name). New startup script bin/casssandra provides out-of-the-box background mode without hacks like screen or nohup; -f flag restores old foreground mode. Also -p to log pid. Patch by Eric Evans for #20 git-svn-id: https://svn.apache.org/repos/asf/incubator/cassandra/trunk@760679 13f79535-47bb-0310-9956-ffa450edef68 --- bin/start-server | 32 ---- bin/stop-server | 16 +- src/org/apache/cassandra/db/DBManager.java | 4 +- .../cassandra/service/CassandraDaemon.java | 137 ++++++++++++++++++ .../cassandra/service/CassandraServer.java | 41 +----- .../cassandra/service/StorageService.java | 2 +- 6 files changed, 156 insertions(+), 76 deletions(-) delete mode 100755 bin/start-server create mode 100644 src/org/apache/cassandra/service/CassandraDaemon.java diff --git a/bin/start-server b/bin/start-server deleted file mode 100755 index 7acbe1cbd7..0000000000 --- a/bin/start-server +++ /dev/null @@ -1,32 +0,0 @@ -#! /usr/bin/env bash -bin=`dirname "$0"` -bin=`cd "$bin"; pwd` - -confpath="$bin/../conf" -cygwin=false -case "`uname`" in -CYGWIN*) cygwin=true;; -esac - - -# CLASSPATH initially contains cassandra jar -CLASSPATH="$bin/../build/cassandra.jar" - -# add libs to CLASSPATH -for f in $bin/../lib/*.jar; do - CLASSPATH=${CLASSPATH}:$f; -done - -CLASSPATH=conf:${CLASSPATH}; - -# cygwin path translation -if $cygwin; then -echo "in cygwin" -echo $CLASSPATH - CLASSPATH=`cygpath -p -w "$CLASSPATH"` -confpath=`cygpath -p -w "$confpath"` -fi - - -# run it -java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8888,suspend=n -Xms128M -Xmx2G -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90 -XX:+AggressiveOpts -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=1 -XX:+CMSParallelRemarkEnabled -XX:+HeapDumpOnOutOfMemoryError -Dcom.sun.management.jmxremote.port=8080 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcassandra -Dstorage-config="$confpath" -cp "$CLASSPATH" org.apache.cassandra.service.CassandraServer & diff --git a/bin/stop-server b/bin/stop-server index 0490123acb..fd6be0ff2e 100755 --- a/bin/stop-server +++ b/bin/stop-server @@ -1,2 +1,14 @@ -user=`whoami` -pgrep -u $user -f cassandra | xargs kill -9 +echo "please read the stop-server script before use" + +# if you are using the cassandra start script with -p, this +# is the best way to stop: + +# kill `cat ` + + +# otherwise, you can run something like this, but +# this is a shotgun approach and will kill other processes +# with cassandra in their name or arguments too: + +# user=`whoami` +# pgrep -u $user -f cassandra | xargs kill diff --git a/src/org/apache/cassandra/db/DBManager.java b/src/org/apache/cassandra/db/DBManager.java index 7a9c6426e5..53cb170313 100644 --- a/src/org/apache/cassandra/db/DBManager.java +++ b/src/org/apache/cassandra/db/DBManager.java @@ -44,7 +44,7 @@ public class DBManager private static DBManager dbMgr_; private static Lock lock_ = new ReentrantLock(); - public static DBManager instance() throws Throwable + public static DBManager instance() throws IOException { if ( dbMgr_ == null ) { @@ -89,7 +89,7 @@ public class DBManager } } - public DBManager() throws Throwable + public DBManager() throws IOException { Set tables = DatabaseDescriptor.getTableToColumnFamilyMap().keySet(); diff --git a/src/org/apache/cassandra/service/CassandraDaemon.java b/src/org/apache/cassandra/service/CassandraDaemon.java new file mode 100644 index 0000000000..4a95dabbb1 --- /dev/null +++ b/src/org/apache/cassandra/service/CassandraDaemon.java @@ -0,0 +1,137 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.service; + +import java.io.File; +import java.io.IOException; + +import org.apache.log4j.Logger; +import com.facebook.thrift.protocol.TBinaryProtocol; +import com.facebook.thrift.protocol.TProtocolFactory; +import com.facebook.thrift.server.TThreadPoolServer; +import com.facebook.thrift.transport.TServerSocket; +import com.facebook.thrift.transport.TTransportException; +import org.apache.cassandra.config.DatabaseDescriptor; + +/** + * This class supports two methods for creating a Cassandra node daemon, + * invoking the class's main method, and using the jsvc wrapper from + * commons-daemon, (for more information on using this class with the + * jsvc wrapper, see the + * Commons Daemon + * documentation). + * + * @author Eric Evans + * + */ + +public class CassandraDaemon +{ + private static Logger logger = Logger.getLogger(CassandraDaemon.class); + private TThreadPoolServer serverEngine; + + private void setup() throws IOException, TTransportException + { + int listenPort = DatabaseDescriptor.getThriftPort(); + + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() + { + public void uncaughtException(Thread t, Throwable e) + { + logger.error("Fatal exception in thread " + t, e); + } + }); + + CassandraServer peerStorageServer = new CassandraServer(); + peerStorageServer.start(); + Cassandra.Processor processor = new Cassandra.Processor(peerStorageServer); + + // Transport + TServerSocket tServerSocket = new TServerSocket(listenPort); + + // Protocol factory + TProtocolFactory tProtocolFactory = new TBinaryProtocol.Factory(); + + // ThreadPool Server + TThreadPoolServer.Options options = new TThreadPoolServer.Options(); + options.minWorkerThreads = 64; + serverEngine = new TThreadPoolServer(processor, tServerSocket, tProtocolFactory); + } + + /** hook for JSVC */ + public void load(String[] args) throws IOException, TTransportException + { + setup(); + } + + /** hook for JSVC */ + public void start() + { + logger.info("Cassandra starting up..."); + serverEngine.serve(); + } + + /** hook for JSVC */ + public void stop() + { + logger.info("Cassandra shutting down..."); + serverEngine.stop(); + } + + + /** hook for JSVC */ + public void destroy() + { + } + + public static void main(String[] args) + { + CassandraDaemon daemon = new CassandraDaemon(); + String pidFile = System.getProperty("cassandra-pidfile"); + + try + { + daemon.setup(); + + if (pidFile != null) + { + new File(pidFile).deleteOnExit(); + } + + if (System.getProperty("cassandra-foreground") == null) + { + System.out.close(); + System.err.close(); + } + + daemon.start(); + } + catch (Exception e) + { + String msg = "Exception encountered during startup."; + logger.error(msg, e); + + // try to warn user on stdout too, if we haven't already detached + System.out.println(msg); + e.printStackTrace(); + + System.exit(3); + } + } +} diff --git a/src/org/apache/cassandra/service/CassandraServer.java b/src/org/apache/cassandra/service/CassandraServer.java index 0d6c814e3a..3bf83a1a43 100644 --- a/src/org/apache/cassandra/service/CassandraServer.java +++ b/src/org/apache/cassandra/service/CassandraServer.java @@ -90,7 +90,7 @@ public class CassandraServer extends FacebookBase implements Cassandra.Iface * The start function initializes the server and start's listening on the * specified port. */ - public void start() throws Throwable + public void start() throws IOException { LogUtil.init(); //LogUtil.setLogLevel("com.facebook", "DEBUG"); @@ -850,42 +850,5 @@ public class CassandraServer extends FacebookBase implements Cassandra.Iface return null; } - public static void main(String[] args) throws Throwable - { - int port = DatabaseDescriptor.getThriftPort(); - - Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() - { - public void uncaughtException(Thread t, Throwable e) - { - logger_.error("Fatal exception in thread " + t, e); - } - }); - - try - { - CassandraServer peerStorageServer = new CassandraServer(); - peerStorageServer.start(); - Cassandra.Processor processor = new Cassandra.Processor( - peerStorageServer); - // Transport - TServerSocket tServerSocket = new TServerSocket(port); - // Protocol factory - TProtocolFactory tProtocolFactory = new TBinaryProtocol.Factory(); - // ThreadPool Server - Options options = new Options(); - options.minWorkerThreads = 64; - TThreadPoolServer serverEngine = new TThreadPoolServer(processor, tServerSocket, tProtocolFactory); - serverEngine.serve(); - - } - catch (Exception x) - { - System.err.println("UNCAUGHT EXCEPTION IN main()"); - x.printStackTrace(); - System.exit(1); - } - - } - + // main method moved to CassandraDaemon } diff --git a/src/org/apache/cassandra/service/StorageService.java b/src/org/apache/cassandra/service/StorageService.java index b5e00c9d91..2f6a0186fe 100644 --- a/src/org/apache/cassandra/service/StorageService.java +++ b/src/org/apache/cassandra/service/StorageService.java @@ -448,7 +448,7 @@ public final class StorageService implements IEndPointStateChangeSubscriber, Sto } } - public void start() throws Throwable + public void start() throws IOException { /* Start the DB */ storageMetadata_ = DBManager.instance().start();