zipkin2.storage.cassandra.v1.Schema.java Source code

Java tutorial

Introduction

Here is the source code for zipkin2.storage.cassandra.v1.Schema.java

Source

/*
 * 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 zipkin2.storage.cassandra.v1;

import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.KeyspaceMetadata;
import com.datastax.driver.core.ProtocolVersion;
import com.datastax.driver.core.Session;
import com.google.common.io.CharStreams;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.google.common.base.Charsets.UTF_8;
import static zipkin2.storage.cassandra.v1.Tables.AUTOCOMPLETE_TAGS;
import static zipkin2.storage.cassandra.v1.Tables.REMOTE_SERVICE_NAMES;

final class Schema {
    private static final Logger LOG = LoggerFactory.getLogger(Schema.class);

    static final String SCHEMA = "/cassandra-schema.cql";
    static final String UPGRADE_1 = "/cassandra-schema-upgrade-1.cql";
    static final String UPGRADE_2 = "/cassandra-schema-upgrade-2.cql";
    static final String UPGRADE_3 = "/cassandra-schema-upgrade-3.cql";

    private Schema() {
    }

    static Metadata readMetadata(Session session) {
        KeyspaceMetadata keyspaceMetadata = getKeyspaceMetadata(session);

        Map<String, String> replication = keyspaceMetadata.getReplication();
        if ("SimpleStrategy".equals(replication.get("class"))
                && "1".equals(replication.get("replication_factor"))) {
            LOG.warn("running with RF=1, this is not suitable for production. Optimal is 3+");
        }
        String compactionClass = keyspaceMetadata.getTable("traces").getOptions().getCompaction().get("class");
        boolean hasDefaultTtl = hasUpgrade1_defaultTtl(keyspaceMetadata);
        if (!hasDefaultTtl) {
            LOG.warn("schema lacks default ttls: apply {}, or set CassandraStorage.ensureSchema=true", UPGRADE_1);
        }
        boolean hasAutocompleteTags = hasUpgrade2_autocompleteTags(keyspaceMetadata);
        if (!hasAutocompleteTags) {
            LOG.warn("schema lacks autocomplete indexing: apply {}, or set CassandraStorage.ensureSchema=true",
                    UPGRADE_2);
        }

        boolean hasRemoteService = hasUpgrade3_remoteService(keyspaceMetadata);
        if (!hasRemoteService) {
            LOG.warn("schema lacks remote service indexing: apply {}, or set CassandraStorage.ensureSchema=true",
                    UPGRADE_3);
        }

        ProtocolVersion protocolVersion = session.getCluster().getConfiguration().getProtocolOptions()
                .getProtocolVersion();

        return new Metadata(protocolVersion, compactionClass, hasDefaultTtl, hasAutocompleteTags, hasRemoteService);
    }

    static final class Metadata {
        final ProtocolVersion protocolVersion;
        final String compactionClass;
        final boolean hasDefaultTtl, hasAutocompleteTags, hasRemoteService;

        Metadata(ProtocolVersion protocolVersion, String compactionClass, boolean hasDefaultTtl,
                boolean hasAutocompleteTags, boolean hasRemoteService) {
            this.protocolVersion = protocolVersion;
            this.compactionClass = compactionClass;
            this.hasDefaultTtl = hasDefaultTtl;
            this.hasAutocompleteTags = hasAutocompleteTags;
            this.hasRemoteService = hasRemoteService;
        }
    }

    static KeyspaceMetadata getKeyspaceMetadata(Session session) {
        String keyspace = session.getLoggedKeyspace();
        Cluster cluster = session.getCluster();
        KeyspaceMetadata keyspaceMetadata = cluster.getMetadata().getKeyspace(keyspace);

        if (keyspaceMetadata == null) {
            throw new IllegalStateException(
                    String.format("Cannot read keyspace metadata for give keyspace: %s and cluster: %s", keyspace,
                            cluster.getClusterName()));
        }
        return keyspaceMetadata;
    }

    static void ensureExists(String keyspace, Session session) {
        KeyspaceMetadata keyspaceMetadata = session.getCluster().getMetadata().getKeyspace(keyspace);
        if (keyspaceMetadata == null || keyspaceMetadata.getTable("traces") == null) {
            LOG.info("Installing schema {}", SCHEMA);
            applyCqlFile(keyspace, session, SCHEMA);
            // refresh metadata since we've installed the schema
            keyspaceMetadata = session.getCluster().getMetadata().getKeyspace(keyspace);
        }
        if (!hasUpgrade1_defaultTtl(keyspaceMetadata)) {
            LOG.info("Upgrading schema {}", UPGRADE_1);
            applyCqlFile(keyspace, session, UPGRADE_1);
        }
        if (!hasUpgrade2_autocompleteTags(keyspaceMetadata)) {
            LOG.info("Upgrading schema {}", UPGRADE_2);
            applyCqlFile(keyspace, session, UPGRADE_2);
        }
        if (!hasUpgrade3_remoteService(keyspaceMetadata)) {
            LOG.info("Upgrading schema {}", UPGRADE_3);
            applyCqlFile(keyspace, session, UPGRADE_3);
        }
    }

    static boolean hasUpgrade1_defaultTtl(KeyspaceMetadata keyspaceMetadata) {
        // TODO: we need some approach to forward-check compatibility as well.
        //  backward: this code knows the current schema is too old.
        //  forward:  this code knows the current schema is too new.
        return keyspaceMetadata.getTable("traces").getOptions().getDefaultTimeToLive() > 0;
    }

    static boolean hasUpgrade2_autocompleteTags(KeyspaceMetadata keyspaceMetadata) {
        return keyspaceMetadata.getTable(AUTOCOMPLETE_TAGS) != null;
    }

    static boolean hasUpgrade3_remoteService(KeyspaceMetadata keyspaceMetadata) {
        return keyspaceMetadata.getTable(REMOTE_SERVICE_NAMES) != null;
    }

    static void applyCqlFile(String keyspace, Session session, String resource) {
        try (Reader reader = new InputStreamReader(Schema.class.getResourceAsStream(resource), UTF_8)) {
            for (String cmd : CharStreams.toString(reader).split(";")) {
                cmd = cmd.trim().replace(" zipkin", " " + keyspace);
                if (!cmd.isEmpty()) {
                    session.execute(cmd);
                }
            }
        } catch (IOException ex) {
            LOG.error(ex.getMessage(), ex);
        }
    }
}