summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/thinkaurelius/titan/diskstorage/cassandra/utils/CassandraDaemonWrapper.java
blob: acd87dbd9949875576df5a41aa3a5adc7f27e75f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package com.thinkaurelius.titan.diskstorage.cassandra.utils;

import java.lang.Thread.UncaughtExceptionHandler;

import org.apache.cassandra.config.Schema;
import org.apache.cassandra.db.commitlog.CommitLog;
import org.apache.cassandra.net.MessagingService;
import org.apache.cassandra.service.CassandraDaemon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class starts a Thrift CassandraDaemon inside the current JVM. This class
 * supports testing and shouldn't be used in production.
 *
 * This class starts Cassandra on the first invocation of
 * {@link CassandraDaemonWrapper#start(String)} in the life of the JVM.
 * Invocations after the first have no effect except that they may log a
 * warning.
 *
 * When the thread that first called {@code #start(String)} dies, a daemon
 * thread returns from {@link Thread#join()} and kills all embedded Cassandra
 * threads in the JVM.
 *
 * This class once supported consecutive, idempotent calls to start(String) so
 * long as the argument was the same in each invocation. It also once used
 * refcounting to kill Cassandra's non-daemon threads once stop() was called as
 * many times as start(). Some of Cassandra's background threads and statics
 * can't be easily reset to allow a restart inside the same JVM, so this was
 * intended as a one-use thing. However, this interacts poorly with the new
 * KCVConfiguration system in titan-core. When KCVConfiguration is in use, core
 * starts and stops each backend at least twice in the course of opening a
 * single database instance. So the old refcounting and killing approach is out.
 *
 * @author Dan LaRocque <dalaro@hopcount.org>
 */
public class CassandraDaemonWrapper {

    private static final Logger log =
            LoggerFactory.getLogger(CassandraDaemonWrapper.class);

    private static String activeConfig;

    private static boolean started;

    public static synchronized void start(String config) {

        if (started) {
            if (null != config && !config.equals(activeConfig)) {
                log.warn("Can't start in-process Cassandra instance " +
                         "with yaml path {} because an instance was " +
                         "previously started with yaml path {}",
                         config, activeConfig);
            }

            return;
        }

        started = true;

        log.debug("Current working directory: {}", System.getProperty("user.dir"));

        System.setProperty("cassandra.config", config);
        // Prevent Cassandra from closing stdout/stderr streams
        System.setProperty("cassandra-foreground", "yes");
        // Prevent Cassandra from overwriting Log4J configuration
        System.setProperty("log4j.defaultInitOverride", "false");

        log.info("Starting cassandra with {}", config);

        /*
         * This main method doesn't block for any substantial length of time. It
         * creates and starts threads and returns in relatively short order.
         */
        CassandraDaemon.main(new String[0]);

        activeConfig = config;
    }

    public static synchronized boolean isStarted() {
        return started;
    }

    public static void stop() {
        // Do nothing
    }
}