/*
* 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.zeppelin.cassandra;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.ProtocolOptions.Compression;
import com.datastax.driver.core.Session;
import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterPropertyBuilder;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.scheduler.Scheduler;
import org.apache.zeppelin.scheduler.SchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import static com.datastax.driver.core.ProtocolOptions.DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS;
import static java.lang.Integer.parseInt;
/**
* Interpreter for Apache Cassandra CQL query language
*/
public class CassandraInterpreter extends Interpreter {
private static final Logger LOGGER = LoggerFactory.getLogger(CassandraInterpreter.class);
public static final String CASSANDRA_INTERPRETER_PARALLELISM = "cassandra.interpreter" +
".parallelism";
public static final String CASSANDRA_HOSTS = "cassandra.hosts";
public static final String CASSANDRA_PORT = "cassandra.native.port";
public static final String CASSANDRA_PROTOCOL_VERSION = "cassandra.protocol.version";
public static final String CASSANDRA_CLUSTER_NAME = "cassandra.cluster";
public static final String CASSANDRA_KEYSPACE_NAME = "cassandra.keyspace";
public static final String CASSANDRA_COMPRESSION_PROTOCOL = "cassandra.compression.protocol";
public static final String CASSANDRA_CREDENTIALS_USERNAME = "cassandra.credentials.username";
public static final String CASSANDRA_CREDENTIALS_PASSWORD = "cassandra.credentials.password";
public static final String CASSANDRA_LOAD_BALANCING_POLICY = "cassandra.load.balancing.policy";
public static final String CASSANDRA_RETRY_POLICY = "cassandra.retry.policy";
public static final String CASSANDRA_RECONNECTION_POLICY = "cassandra.reconnection.policy";
public static final String CASSANDRA_SPECULATIVE_EXECUTION_POLICY =
"cassandra.speculative.execution.policy";
public static final String CASSANDRA_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS =
"cassandra.max.schema.agreement.wait.second";
public static final String CASSANDRA_POOLING_NEW_CONNECTION_THRESHOLD_LOCAL =
"cassandra.pooling.new.connection.threshold.local";
public static final String CASSANDRA_POOLING_NEW_CONNECTION_THRESHOLD_REMOTE =
"cassandra.pooling.new.connection.threshold.remote";
public static final String CASSANDRA_POOLING_MAX_CONNECTION_PER_HOST_LOCAL =
"cassandra.pooling.max.connection.per.host.local";
public static final String CASSANDRA_POOLING_MAX_CONNECTION_PER_HOST_REMOTE =
"cassandra.pooling.max.connection.per.host.remote";
public static final String CASSANDRA_POOLING_CORE_CONNECTION_PER_HOST_LOCAL =
"cassandra.pooling.core.connection.per.host.local";
public static final String CASSANDRA_POOLING_CORE_CONNECTION_PER_HOST_REMOTE =
"cassandra.pooling.core.connection.per.host.remote";
public static final String CASSANDRA_POOLING_MAX_REQUESTS_PER_CONNECTION_LOCAL =
"cassandra.pooling.max.request.per.connection.local";
public static final String CASSANDRA_POOLING_MAX_REQUESTS_PER_CONNECTION_REMOTE =
"cassandra.pooling.max.request.per.connection.remote";
public static final String CASSANDRA_POOLING_IDLE_TIMEOUT_SECONDS =
"cassandra.pooling.idle.timeout.seconds";
public static final String CASSANDRA_POOLING_POOL_TIMEOUT_MILLIS =
"cassandra.pooling.pool.timeout.millisecs";
public static final String CASSANDRA_POOLING_HEARTBEAT_INTERVAL_SECONDS =
"cassandra.pooling.heartbeat.interval.seconds";
public static final String CASSANDRA_QUERY_DEFAULT_CONSISTENCY =
"cassandra.query.default.consistency";
public static final String CASSANDRA_QUERY_DEFAULT_SERIAL_CONSISTENCY =
"cassandra.query.default.serial.consistency";
public static final String CASSANDRA_QUERY_DEFAULT_FETCH_SIZE =
"cassandra.query.default.fetchSize";
public static final String CASSANDRA_QUERY_DEFAULT_IDEMPOTENCE =
"cassandra.query.default.idempotence";
public static final String CASSANDRA_SOCKET_CONNECTION_TIMEOUT_MILLIS =
"cassandra.socket.connection.timeout.millisecs";
public static final String CASSANDRA_SOCKET_KEEP_ALIVE =
"cassandra.socket.keep.alive";
public static final String CASSANDRA_SOCKET_READ_TIMEOUT_MILLIS =
"cassandra.socket.read.timeout.millisecs";
public static final String CASSANDRA_SOCKET_RECEIVED_BUFFER_SIZE_BYTES =
"cassandra.socket.received.buffer.size.bytes";
public static final String CASSANDRA_SOCKET_REUSE_ADDRESS =
"cassandra.socket.reuse.address";
public static final String CASSANDRA_SOCKET_SEND_BUFFER_SIZE_BYTES =
"cassandra.socket.send.buffer.size.bytes";
public static final String CASSANDRA_SOCKET_SO_LINGER =
"cassandra.socket.soLinger";
public static final String CASSANDRA_SOCKET_TCP_NO_DELAY =
"cassandra.socket.tcp.no_delay";
public static final String DEFAULT_HOST = "localhost";
public static final String DEFAULT_PORT = "9042";
public static final String DEFAULT_CLUSTER = "Test Cluster";
public static final String DEFAULT_KEYSPACE = "system";
public static final String DEFAULT_PROTOCOL_VERSION = "3";
public static final String DEFAULT_COMPRESSION = "NONE";
public static final String DEFAULT_CREDENTIAL = "none";
public static final String DEFAULT_POLICY = "DEFAULT";
public static final String DEFAULT_PARALLELISM = "10";
static String DEFAULT_NEW_CONNECTION_THRESHOLD_LOCAL = "100";
static String DEFAULT_NEW_CONNECTION_THRESHOLD_REMOTE = "100";
static String DEFAULT_CORE_CONNECTION_PER_HOST_LOCAL = "2";
static String DEFAULT_CORE_CONNECTION_PER_HOST_REMOTE = "1";
static String DEFAULT_MAX_CONNECTION_PER_HOST_LOCAL = "8";
static String DEFAULT_MAX_CONNECTION_PER_HOST_REMOTE = "2";
static String DEFAULT_MAX_REQUEST_PER_CONNECTION_LOCAL = "1024";
static String DEFAULT_MAX_REQUEST_PER_CONNECTION_REMOTE = "256";
public static final String DEFAULT_IDLE_TIMEOUT = "120";
public static final String DEFAULT_POOL_TIMEOUT = "5000";
public static final String DEFAULT_HEARTBEAT_INTERVAL = "30";
public static final String DEFAULT_CONSISTENCY = "ONE";
public static final String DEFAULT_SERIAL_CONSISTENCY = "SERIAL";
public static final String DEFAULT_FETCH_SIZE = "5000";
public static final String DEFAULT_CONNECTION_TIMEOUT = "5000";
public static final String DEFAULT_READ_TIMEOUT = "12000";
public static final String DEFAULT_TCP_NO_DELAY = "true";
public static final String DOWNGRADING_CONSISTENCY_RETRY = "DOWNGRADING_CONSISTENCY";
public static final String FALLTHROUGH_RETRY = "FALLTHROUGH";
public static final String LOGGING_DEFAULT_RETRY = "LOGGING_DEFAULT";
public static final String LOGGING_DOWNGRADING_RETRY = "LOGGING_DOWNGRADING";
public static final String LOGGING_FALLTHROUGH_RETRY = "LOGGING_FALLTHROUGH";
public static final List<String> NO_COMPLETION = new ArrayList<>();
InterpreterLogic helper;
Cluster cluster;
Session session;
private JavaDriverConfig driverConfig = new JavaDriverConfig();
public CassandraInterpreter(Properties properties) {
super(properties);
}
static {
LOGGER.info("Bootstrapping Cassandra Interpreter");
Interpreter.register("cassandra", "cassandra", CassandraInterpreter.class.getName(),
new InterpreterPropertyBuilder()
.add(CASSANDRA_HOSTS, DEFAULT_HOST,
"Comma separated Cassandra hosts (DNS name or " +
"IP address). Default = localhost. Ex: '192.168.0.12,node2,node3'")
.add(CASSANDRA_PORT, DEFAULT_PORT, "Cassandra native port. Default = 9042")
.add(CASSANDRA_PROTOCOL_VERSION, DEFAULT_PROTOCOL_VERSION,
"Cassandra protocol version. Default = 3")
.add(CASSANDRA_CLUSTER_NAME, DEFAULT_CLUSTER, "Cassandra cluster name. " +
"Default = 'Test Cluster'")
.add(CASSANDRA_KEYSPACE_NAME, DEFAULT_KEYSPACE, "Cassandra keyspace name. " +
"Default = 'system'")
.add(CASSANDRA_COMPRESSION_PROTOCOL, DEFAULT_COMPRESSION,
"Cassandra compression protocol. " +
"Available values: NONE, SNAPPY, LZ4. Default = NONE")
.add(CASSANDRA_CREDENTIALS_USERNAME, DEFAULT_CREDENTIAL,
"Cassandra credentials username. " +
"Default = 'none'")
.add(CASSANDRA_CREDENTIALS_PASSWORD, DEFAULT_CREDENTIAL,
"Cassandra credentials password. " +
"Default = 'none'")
.add(CASSANDRA_LOAD_BALANCING_POLICY, DEFAULT_POLICY, "Cassandra Load Balancing Policy. " +
"Default = new TokenAwarePolicy(new DCAwareRoundRobinPolicy())")
.add(CASSANDRA_RETRY_POLICY, DEFAULT_POLICY, "Cassandra Retry Policy. " +
"Default = DefaultRetryPolicy.INSTANCE")
.add(CASSANDRA_RECONNECTION_POLICY, DEFAULT_POLICY, "Cassandra Reconnection Policy. " +
"Default = new ExponentialReconnectionPolicy(1000, 10 * 60 * 1000)")
.add(CASSANDRA_SPECULATIVE_EXECUTION_POLICY, DEFAULT_POLICY,
"Cassandra Speculative Execution Policy. " +
"Default = NoSpeculativeExecutionPolicy.INSTANCE")
.add(CASSANDRA_INTERPRETER_PARALLELISM, DEFAULT_PARALLELISM,
"Cassandra interpreter parallelism" +
".Default = 10")
.add(CASSANDRA_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS,
DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS + ""
, "Cassandra max schema agreement wait in second" +
".Default = ProtocolOptions.DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS")
.add(CASSANDRA_POOLING_NEW_CONNECTION_THRESHOLD_LOCAL,
DEFAULT_NEW_CONNECTION_THRESHOLD_LOCAL,
"Cassandra new connection threshold local. " +
"Protocol V2 and below default = 100" +
"Protocol V3 and above default = 800")
.add(CASSANDRA_POOLING_NEW_CONNECTION_THRESHOLD_REMOTE,
DEFAULT_NEW_CONNECTION_THRESHOLD_REMOTE,
"Cassandra new connection threshold remove. " +
"Protocol V2 and below default = 100" +
"Protocol V3 and above default = 200")
.add(CASSANDRA_POOLING_CORE_CONNECTION_PER_HOST_LOCAL,
DEFAULT_CORE_CONNECTION_PER_HOST_LOCAL,
"Cassandra core connection per host local. " +
"Protocol V2 and below default = 2" +
"Protocol V3 and above default = 1")
.add(CASSANDRA_POOLING_CORE_CONNECTION_PER_HOST_REMOTE,
DEFAULT_CORE_CONNECTION_PER_HOST_REMOTE,
"Cassandra core connection per host remove. " +
"Protocol V2 and below default = 1" +
"Protocol V3 and above default = 1")
.add(CASSANDRA_POOLING_MAX_CONNECTION_PER_HOST_LOCAL,
DEFAULT_MAX_CONNECTION_PER_HOST_LOCAL,
"Cassandra max connection per host local. " +
"Protocol V2 and below default = 8" +
"Protocol V3 and above default = 1")
.add(CASSANDRA_POOLING_MAX_CONNECTION_PER_HOST_REMOTE,
DEFAULT_MAX_CONNECTION_PER_HOST_REMOTE,
"Cassandra max connection per host remote. " +
"Protocol V2 and below default = 2" +
"Protocol V3 and above default = 1")
.add(CASSANDRA_POOLING_MAX_REQUESTS_PER_CONNECTION_LOCAL,
DEFAULT_MAX_REQUEST_PER_CONNECTION_LOCAL,
"Cassandra max request per connection local. " +
"Protocol V2 and below default = 128" +
"Protocol V3 and above default = 1024")
.add(CASSANDRA_POOLING_MAX_REQUESTS_PER_CONNECTION_REMOTE,
DEFAULT_MAX_REQUEST_PER_CONNECTION_REMOTE,
"Cassandra max request per connection remote. " +
"Protocol V2 and below default = 128" +
"Protocol V3 and above default = 256")
.add(CASSANDRA_POOLING_IDLE_TIMEOUT_SECONDS, DEFAULT_IDLE_TIMEOUT,
"Cassandra idle time out in seconds. Default = 120")
.add(CASSANDRA_POOLING_POOL_TIMEOUT_MILLIS, DEFAULT_POOL_TIMEOUT,
"Cassandra pool time out in millisecs. Default = 5000")
.add(CASSANDRA_POOLING_HEARTBEAT_INTERVAL_SECONDS, DEFAULT_HEARTBEAT_INTERVAL,
"Cassandra pool heartbeat interval in secs. Default = 30")
.add(CASSANDRA_QUERY_DEFAULT_CONSISTENCY, DEFAULT_CONSISTENCY,
"Cassandra query default consistency level. Default = ONE")
.add(CASSANDRA_QUERY_DEFAULT_SERIAL_CONSISTENCY, DEFAULT_SERIAL_CONSISTENCY,
"Cassandra query default serial consistency level. Default = SERIAL")
.add(CASSANDRA_QUERY_DEFAULT_FETCH_SIZE, DEFAULT_FETCH_SIZE,
"Cassandra query default fetch size. Default = 5000")
.add(CASSANDRA_SOCKET_CONNECTION_TIMEOUT_MILLIS, DEFAULT_CONNECTION_TIMEOUT,
"Cassandra socket default connection timeout in millisecs. Default = 5000")
.add(CASSANDRA_SOCKET_READ_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT,
"Cassandra socket read timeout in millisecs. Default = 12000")
.add(CASSANDRA_SOCKET_TCP_NO_DELAY, DEFAULT_TCP_NO_DELAY,
"Cassandra socket TCP no delay. Default = true")
.build());
}
@Override
public void open() {
final String[] addresses = getProperty(CASSANDRA_HOSTS).split(",");
final int port = parseInt(getProperty(CASSANDRA_PORT));
StringBuilder hosts = new StringBuilder();
for (String address : addresses) {
hosts.append(address).append(",");
}
LOGGER.info("Bootstrapping Cassandra Java Driver to connect to " + hosts.toString() +
"on port " + port);
Compression compression = driverConfig.getCompressionProtocol(this);
cluster = Cluster.builder()
.addContactPoints(addresses)
.withPort(port)
.withProtocolVersion(driverConfig.getProtocolVersion(this))
.withClusterName(getProperty(CASSANDRA_CLUSTER_NAME))
.withCompression(compression)
.withCredentials(getProperty(CASSANDRA_CREDENTIALS_USERNAME),
getProperty(CASSANDRA_CREDENTIALS_PASSWORD))
.withLoadBalancingPolicy(driverConfig.getLoadBalancingPolicy(this))
.withRetryPolicy(driverConfig.getRetryPolicy(this))
.withReconnectionPolicy(driverConfig.getReconnectionPolicy(this))
.withSpeculativeExecutionPolicy(driverConfig.getSpeculativeExecutionPolicy(this))
.withMaxSchemaAgreementWaitSeconds(
parseInt(getProperty(CASSANDRA_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS)))
.withPoolingOptions(driverConfig.getPoolingOptions(this))
.withQueryOptions(driverConfig.getQueryOptions(this))
.withSocketOptions(driverConfig.getSocketOptions(this))
.build();
session = cluster.connect();
helper = new InterpreterLogic(session);
}
@Override
public void close() {
session.close();
cluster.close();
}
@Override
public InterpreterResult interpret(String st, InterpreterContext context) {
return helper.interpret(session, st, context);
}
@Override
public void cancel(InterpreterContext context) {
}
@Override
public FormType getFormType() {
return FormType.NATIVE;
}
@Override
public int getProgress(InterpreterContext context) {
return 0;
}
@Override
public List<String> completion(String buf, int cursor) {
return NO_COMPLETION;
}
@Override
public Scheduler getScheduler() {
return SchedulerFactory.singleton()
.createOrGetParallelScheduler(CassandraInterpreter.class.getName() + this.hashCode(),
parseInt(getProperty(CASSANDRA_INTERPRETER_PARALLELISM)));
}
@Override
public void destroy() {
super.destroy();
this.close();
}
}