All Downloads are FREE. Search and download functionalities are using the official Maven repository.

info.archinnov.achilles.embedded.AchillesCassandraDaemon Maven / Gradle / Ivy

There is a newer version: 6.1.0
Show newest version
/*
 * Copyright (C) 2012-2016 DuyHai DOAN
 *
 * Licensed 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 info.archinnov.achilles.embedded;

import java.io.IOException;
import java.util.List;

import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.Schema;
import org.apache.cassandra.cql3.functions.ThreadAwareSecurityManager;
import org.apache.cassandra.db.*;
import org.apache.cassandra.db.commitlog.CommitLog;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.io.FSError;
import org.apache.cassandra.io.sstable.CorruptSSTableException;
import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.metrics.StorageMetrics;
import org.apache.cassandra.service.*;
import org.apache.cassandra.tracing.Tracing;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.JVMStabilityInspector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

public class AchillesCassandraDaemon extends CassandraDaemon {

    private static final Logger logger = LoggerFactory.getLogger(AchillesCassandraDaemon.class);
    private NativeTransportService nativeTransportService;
    /**
     * Override the default setup process to speed up bootstrap
     *
     * - disable JMX
     * - disable legacy schema migration
     * - no pre-3.0 hints migration
     * - no pre-3.0 batch entries migration
     * - disable auto compaction on all keyspaces (your test data should fit in memory!!!)
     * - disable metrics
     * - disable GCInspector
     * - disable mlock
     * - disable Thrift server
     * - disable startup checks (Jemalloc, validLaunchDate, JMXPorts, JvmOptions, JnaInitialization, initSigarLibrary, dataDirs, SSTablesFormat, SystemKeyspaceState, Datacenter, Rack)
     * - disable materialized view rebuild (you should clean data folder between each test anyway)
     * - disable the SizeEstimatesRecorder (estimate SSTable size, who cares for unit testing ?)
     */
    @Override
    protected void setup() {
        // Delete any failed snapshot deletions on Windows - see CASSANDRA-9658
        if (FBUtilities.isWindows())
            WindowsFailedSnapshotTracker.deleteOldSnapshots();

        ThreadAwareSecurityManager.install();

        Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
            StorageMetrics.exceptions.inc();
            logger.error("Exception in thread {}", t, e);
            Tracing.trace("Exception in thread {}", t, e);
            for (Throwable e2 = e; e2 != null; e2 = e2.getCause())
            {
                JVMStabilityInspector.inspectThrowable(e2);

                if (e2 instanceof FSError)
                {
                    if (e2 != e) // make sure FSError gets logged exactly once.
                        logger.error("Exception in thread {}", t, e2);
                    FileUtils.handleFSError((FSError) e2);
                }

                if (e2 instanceof CorruptSSTableException)
                {
                    if (e2 != e)
                        logger.error("Exception in thread " + t, e2);
                    FileUtils.handleCorruptSSTable((CorruptSSTableException) e2);
                }
            }
        });

        // load schema from disk
        Schema.instance.loadFromDisk();

        // clean up debris in the rest of the keyspaces
        for (String keyspaceName : Schema.instance.getKeyspaces())
        {
            // Skip system as we've already cleaned it
            if (keyspaceName.equals(SystemKeyspace.NAME))
                continue;

            for (CFMetaData cfm : Schema.instance.getTablesAndViews(keyspaceName))
                ColumnFamilyStore.scrubDataDirectories(cfm);
        }

        Keyspace.setInitialized();

        // initialize keyspaces
        for (String keyspaceName : Schema.instance.getKeyspaces())
        {
            if (logger.isDebugEnabled())
                logger.debug("opening keyspace {}", keyspaceName);
            // disable auto compaction until commit log replay ends
            for (ColumnFamilyStore cfs : Keyspace.open(keyspaceName).getColumnFamilyStores())
            {
                for (ColumnFamilyStore store : cfs.concatWithIndexes())
                {
                    store.disableAutoCompaction();
                }
            }
        }


        try
        {
            loadRowAndKeyCacheAsync().get();
        }
        catch (Throwable t)
        {
            JVMStabilityInspector.inspectThrowable(t);
            logger.warn("Error loading key or row cache", t);
        }

        // replay the log if necessary
        try
        {
            CommitLog.instance.recover();
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }

        // Re-populate token metadata after commit log recover (new peers might be loaded onto system keyspace #10293)
        StorageService.instance.populateTokenMetadata();

        SystemKeyspace.finishStartup();

        // start server internals
        StorageService.instance.registerDaemon(this);
        try
        {
            StorageService.instance.initServer();
        }
        catch (ConfigurationException e)
        {
            System.err.println(e.getMessage() + "\nFatal configuration error; unable to start server.  See log for stacktrace.");
            exitOrFail(1, "Fatal configuration error", e);
        }

        // Native transport
        nativeTransportService = new NativeTransportService();

        completeSetup();
    }

    private void exitOrFail(int code, String message, Throwable cause)
    {
        logger.error(message, cause);
        System.exit(code);
    }

    private ListenableFuture loadRowAndKeyCacheAsync()
    {
        final ListenableFuture keyCacheLoad = CacheService.instance.keyCache.loadSavedAsync();

        final ListenableFuture rowCacheLoad = CacheService.instance.rowCache.loadSavedAsync();

        @SuppressWarnings("unchecked")
        ListenableFuture> retval = Futures.successfulAsList(keyCacheLoad, rowCacheLoad);

        return retval;
    }

    /**
     * Start the Cassandra Daemon, assuming that it has already been
     * initialized via {@link #init(String[])}
     *
     * Hook for JSVC
     */
    @Override
    public void start()
    {
        startNativeTransport();
        StorageService.instance.setRpcReady(true);
    }

    /**
     * Stop the daemon, ideally in an idempotent manner.
     *
     * Hook for JSVC / Procrun
     */
    @Override
    public void stop()
    {
        // On linux, this doesn't entirely shut down Cassandra, just the RPC server.
        // jsvc takes care of taking the rest down
        logger.info("Cassandra shutting down...");
        if (nativeTransportService != null)
            nativeTransportService.destroy();
        StorageService.instance.setRpcReady(false);

        // On windows, we need to stop the entire system as prunsrv doesn't have the jsvc hooks
        // We rely on the shutdown hook to drain the node
        if (FBUtilities.isWindows())
            System.exit(0);
    }

    @Override
    public void startNativeTransport()
    {
        if (nativeTransportService == null)
            throw new IllegalStateException("setup() must be called first for CassandraDaemon");
        else
            nativeTransportService.start();
    }

    @Override
    public void stopNativeTransport()
    {
        if (nativeTransportService != null)
            nativeTransportService.stop();
    }

    @Override
    public boolean isNativeTransportRunning()
    {
        return nativeTransportService != null ? nativeTransportService.isRunning() : false;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy