Current section

Files

Jump to
erlcass c_src nif_cass_cluster.cc
Raw

c_src/nif_cass_cluster.cc

#include "nif_cass_cluster.h"
#include "erlcass.h"
#include "nif_utils.h"
#include "constants.h"
#include "macros.h"
#include <string.h>
#include <memory>
// CassCluster
#define STRING_SETTING(Key, Func) \
if(enif_is_identical(term_key, Key)) { \
ErlNifBinary value; \
if(!get_bstring(env, term_value, &value)) \
return make_bad_options(env, term_option); \
return cass_error_to_nif_term(env, Func(data->cluster, BIN_TO_STR(value.data), value.size)); \
}
#define BOOL_SETTING(Key, Func) \
if(enif_is_identical(term_key, Key)) { \
cass_bool_t value; \
if(!get_boolean(term_value, &value)) \
return make_bad_options(env, term_option); \
return cass_error_to_nif_term(env, Func(data->cluster, value)); \
}
#define INT_SETTING(Key, Func) \
if(enif_is_identical(term_key, Key)) { \
int value; \
if(!enif_get_int(env, term_value, &value)) \
return make_bad_options(env, term_option); \
return cass_error_to_nif_term(env, Func(data->cluster, value)); \
}
#define UNSIGNED_INT_SETTING(Key, Func) \
if(enif_is_identical(term_key, Key)) { \
unsigned int value; \
if(!enif_get_uint(env, term_value, &value)) \
return make_bad_options(env, term_option); \
return cass_error_to_nif_term(env, Func(data->cluster, value)); \
}
#define UINT64_SETTING(Key, Func) \
if(enif_is_identical(term_key, Key)) { \
unsigned long value; \
if(!enif_get_uint64(env, term_value, &value)) \
return make_bad_options(env, term_option); \
return cass_error_to_nif_term(env, Func(data->cluster, static_cast<cass_uint64_t>(value))); \
}
#define CUSTOM_SETTING(Key, Func) \
if(enif_is_identical(term_key, Key)) \
return Func(env, term_option, term_value, data);
CassError internal_cass_cluster_set_connect_timeout(CassCluster* cluster, unsigned timeout)
{
cass_cluster_set_connect_timeout(cluster, timeout);
return CASS_OK;
}
CassError internal_cass_cluster_set_request_timeout(CassCluster* cluster, unsigned timeout)
{
cass_cluster_set_request_timeout(cluster, timeout);
return CASS_OK;
}
CassError internal_cass_cluster_set_connection_heartbeat_interval(CassCluster* cluster, unsigned interval)
{
cass_cluster_set_connection_heartbeat_interval(cluster, interval);
return CASS_OK;
}
CassError internal_cass_cluster_set_connection_idle_timeout(CassCluster* cluster, unsigned timeout)
{
cass_cluster_set_connection_idle_timeout(cluster, timeout);
return CASS_OK;
}
CassError internal_cass_cluster_set_constant_reconnect(CassCluster* cluster, cass_uint64_t delay_ms)
{
cass_cluster_set_constant_reconnect(cluster, delay_ms);
return CASS_OK;
}
CassError internal_cass_cluster_set_max_schema_wait_time(CassCluster* cluster, unsigned wait_time_ms)
{
cass_cluster_set_max_schema_wait_time(cluster, wait_time_ms);
return CASS_OK;
}
ERL_NIF_TERM internal_cass_cluster_set_exponential_reconnect(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
const ERL_NIF_TERM* items;
int arity;
if(!enif_get_tuple(env, term_value, &arity, &items) || arity != 2)
return make_badarg(env);
unsigned long base_delay_ms;
unsigned long max_delay_ms;
if(!enif_get_uint64(env, items[0], &base_delay_ms) || !enif_get_uint64(env, items[1], &max_delay_ms))
return make_bad_options(env, term_option);
return cass_error_to_nif_term(env, cass_cluster_set_exponential_reconnect(data->cluster, base_delay_ms, max_delay_ms));
}
ERL_NIF_TERM internal_set_speculative_execution_policy(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
CassError error = CASS_OK;
if(enif_is_identical(ATOMS.atomNull, term_value))
{
error = cass_cluster_set_no_speculative_execution_policy(data->cluster);
}
else
{
const ERL_NIF_TERM* items;
int arity;
if(!enif_get_tuple(env, term_value, &arity, &items) || arity != 2)
return make_badarg(env);
unsigned long constant_delay_ms;
int max_speculative_executions;
if(!enif_get_uint64(env, items[0], &constant_delay_ms) || !enif_get_int(env, items[1], &max_speculative_executions))
return make_bad_options(env, term_option);
error = cass_cluster_set_constant_speculative_execution_policy(data->cluster, constant_delay_ms, max_speculative_executions);
}
return cass_error_to_nif_term(env, error);
}
ERL_NIF_TERM internal_cass_cluster_set_token_aware_routing_shuffle_replicas(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
cass_bool_t enabled;
if(!get_boolean(term_value, &enabled))
return make_bad_options(env, term_option);
cass_cluster_set_token_aware_routing_shuffle_replicas(data->cluster, enabled);
return ATOMS.atomOk;
}
ERL_NIF_TERM internal_cass_cluster_set_token_aware_routing(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
cass_bool_t token_aware_routing;
if(!get_boolean(term_value, &token_aware_routing))
return make_bad_options(env, term_option);
cass_cluster_set_token_aware_routing(data->cluster, token_aware_routing);
return ATOMS.atomOk;
}
ERL_NIF_TERM internal_cass_cluster_set_tcp_nodelay(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
cass_bool_t nodelay;
if(!get_boolean(term_value, &nodelay))
return make_bad_options(env, term_option);
cass_cluster_set_tcp_nodelay(data->cluster, nodelay);
return ATOMS.atomOk;
}
ERL_NIF_TERM internal_cass_cluster_set_load_balance_round_robin(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
cass_cluster_set_load_balance_round_robin(data->cluster);
return ATOMS.atomOk;
}
ERL_NIF_TERM internal_cass_cluster_set_credentials(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
const ERL_NIF_TERM* items;
int arity;
if(!enif_get_tuple(env, term_value, &arity, &items) || arity != 2)
return make_bad_options(env, term_option);
ErlNifBinary username;
ErlNifBinary pwd;
if(!get_bstring(env, items[0], &username) || !get_bstring(env, items[1], &pwd))
return make_bad_options(env, term_option);
cass_cluster_set_credentials_n(data->cluster, BIN_TO_STR(username.data), username.size, BIN_TO_STR(pwd.data), pwd.size);
return ATOMS.atomOk;
}
ERL_NIF_TERM internal_cass_cluster_set_load_balance_dc_aware(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
const ERL_NIF_TERM* items;
int arity;
if(!enif_get_tuple(env, term_value, &arity, &items) || arity != 3)
return make_bad_options(env, term_option);
ErlNifBinary local_dc;
unsigned int used_hosts_per_remote_dc;
if(!get_bstring(env, items[0], &local_dc) || !enif_get_uint(env, items[1], &used_hosts_per_remote_dc))
return make_bad_options(env, term_option);
cass_bool_t allow_remote_dcs_for_local_cl;
if(!get_boolean(items[2], &allow_remote_dcs_for_local_cl))
return make_bad_options(env, term_option);
return cass_error_to_nif_term(env, cass_cluster_set_load_balance_dc_aware_n(data->cluster,
BIN_TO_STR(local_dc.data),
local_dc.size,
used_hosts_per_remote_dc,
allow_remote_dcs_for_local_cl));
}
ERL_NIF_TERM internal_cass_cluster_set_tcp_keepalive(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
const ERL_NIF_TERM* items;
int arity;
if(!enif_get_tuple(env, term_value, &arity, &items) || arity != 2)
return make_bad_options(env, term_option);
unsigned delay_sec;
cass_bool_t tcp_keepalive;
if(!get_boolean(items[0], &tcp_keepalive))
return make_bad_options(env, term_option);
if(!enif_get_uint(env, items[1], &delay_sec))
return make_bad_options(env, term_option);
cass_cluster_set_tcp_keepalive(data->cluster, tcp_keepalive, delay_sec);
return ATOMS.atomOk;
}
ERL_NIF_TERM internal_cluster_set_default_consistency_level(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
int level;
if(!enif_get_int(env, term_value, &level))
return make_bad_options(env, term_option);
data->defaultConsistencyLevel = static_cast<CassConsistency>(level);
return ATOMS.atomOk;
}
ERL_NIF_TERM internal_cluster_set_retry_policy(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
cass_bool_t log_enable = cass_false;
ERL_NIF_TERM rp = term_value;
if(enif_is_tuple(env, term_value))
{
const ERL_NIF_TERM* items;
int arity;
if(!enif_get_tuple(env, term_value, &arity, &items) || arity != 2)
return make_bad_options(env, term_option);
if(!get_boolean(items[1], &log_enable))
return make_bad_options(env, term_option);
rp = items[0];
}
scoped_ptr(retry_policy, CassRetryPolicy, NULL, cass_retry_policy_free);
scoped_ptr(retry_policy_log, CassRetryPolicy, NULL, cass_retry_policy_free);
if(enif_is_identical(rp, ATOMS.atomClusterSettingRetryPolicyDefault))
retry_policy.reset(cass_retry_policy_default_new());
else if(enif_is_identical(rp, ATOMS.atomClusterSettingRetryPolicyFallthrough))
retry_policy.reset(cass_retry_policy_fallthrough_new());
else
return make_bad_options(env, term_option);
if(log_enable)
{
retry_policy_log.reset(cass_retry_policy_logging_new(retry_policy.get()));
cass_cluster_set_retry_policy(data->cluster, retry_policy_log.get());
}
else
{
cass_cluster_set_retry_policy(data->cluster, retry_policy.get());
}
return ATOMS.atomOk;
}
ERL_NIF_TERM internal_cass_cluster_set_ssl(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
if(!enif_is_list(env, term_value))
return make_bad_options(env, term_option);
ERL_NIF_TERM head;
scoped_ptr(ssl, CassSsl, cass_ssl_new(), cass_ssl_free);
while(enif_get_list_cell(env, term_value, &head, &term_value))
{
const ERL_NIF_TERM* items;
int arity;
if(!enif_get_tuple(env, head, &arity, &items) || arity != 2)
return make_bad_options(env, head);
if(enif_is_identical(items[0], ATOMS.atomClusterSettingSslTrustedCerts))
{
ERL_NIF_TERM trust_list = items[1];
ERL_NIF_TERM cert_head;
ErlNifBinary cert_item;
while(enif_get_list_cell(env, trust_list, &cert_head, &trust_list))
{
if(!get_bstring(env, cert_head, &cert_item))
return make_bad_options(env, head);
CassError error = cass_ssl_add_trusted_cert_n(ssl.get(), BIN_TO_STR(cert_item.data), cert_item.size);
if(error != CASS_OK)
return cass_error_to_nif_term(env, error);
}
}
else if(enif_is_identical(items[0], ATOMS.atomClusterSettingSslCert))
{
ErlNifBinary cert;
if(!get_bstring(env, items[1], &cert))
return make_bad_options(env, head);
CassError error = cass_ssl_set_cert_n(ssl.get(), BIN_TO_STR(cert.data), cert.size);
if(error != CASS_OK)
return cass_error_to_nif_term(env, error);
}
else if(enif_is_identical(items[0], ATOMS.atomClusterSettingSslPrivateKey))
{
const ERL_NIF_TERM* pk_items;
int pk_arity;
ErlNifBinary pk;
ErlNifBinary pk_pwd;
if(!enif_get_tuple(env, items[1], &pk_arity, &pk_items) || pk_arity != 2)
return make_bad_options(env, head);
if(!get_bstring(env, pk_items[0], &pk))
return make_bad_options(env, head);
if(!get_bstring(env, pk_items[1], &pk_pwd))
return make_bad_options(env, head);
CassError error = cass_ssl_set_private_key_n(ssl.get(), BIN_TO_STR(pk.data), pk.size, BIN_TO_STR(pk_pwd.data), pk_pwd.size);
if(error != CASS_OK)
return cass_error_to_nif_term(env, error);
}
else if(enif_is_identical(items[0], ATOMS.atomClusterSettingSslVerifyFlags))
{
int verify_flags;
if(!enif_get_int(env, items[1], &verify_flags))
return make_bad_options(env, head);
cass_ssl_set_verify_flags(ssl.get(), verify_flags);
}
else
{
return make_bad_options(env, head);
}
}
cass_cluster_set_ssl(data->cluster, ssl.get());
return ATOMS.atomOk;
}
ERL_NIF_TERM internal_cluster_set_latency_aware_routing(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_value, cassandra_data* data)
{
if(enif_is_atom(env, term_value))
{
// only enable/disable
cass_bool_t latency_aware_routing;
if(!get_boolean(term_value, &latency_aware_routing))
return make_bad_options(env, term_option);
cass_cluster_set_latency_aware_routing(data->cluster, latency_aware_routing);
return ATOMS.atomOk;
}
const ERL_NIF_TERM* items;
int arity;
if(!enif_get_tuple(env, term_value, &arity, &items) || arity != 2)
return make_bad_options(env, term_option);
cass_bool_t latency_aware_routing;
if(!get_boolean(items[0], &latency_aware_routing))
return make_bad_options(env, term_option);
cass_cluster_set_latency_aware_routing(data->cluster, latency_aware_routing);
// set also the settings
if(!enif_get_tuple(env, items[1], &arity, &items) || arity != 5)
return make_bad_options(env, term_option);
double exclusion_threshold;
unsigned long scale_ms;
unsigned long retry_period_ms;
unsigned long update_rate_ms;
unsigned long min_measured;
if(!enif_get_double(env, items[0], &exclusion_threshold))
return make_bad_options(env, term_option);
if(!enif_get_uint64(env, items[1], &scale_ms))
return make_bad_options(env, term_option);
if(!enif_get_uint64(env, items[2], &retry_period_ms))
return make_bad_options(env, term_option);
if(!enif_get_uint64(env, items[3], &update_rate_ms))
return make_bad_options(env, term_option);
if(!enif_get_uint64(env, items[4], &min_measured))
return make_bad_options(env, term_option);
cass_cluster_set_latency_aware_routing_settings(data->cluster, exclusion_threshold, scale_ms, retry_period_ms, update_rate_ms, min_measured);
return ATOMS.atomOk;
}
ERL_NIF_TERM apply_cluster_settings(ErlNifEnv* env, ERL_NIF_TERM term_option, ERL_NIF_TERM term_key, ERL_NIF_TERM term_value, cassandra_data* data)
{
CUSTOM_SETTING(ATOMS.atomClusterDefaultConsistencyLevel, internal_cluster_set_default_consistency_level);
STRING_SETTING(ATOMS.atomClusterSettingContactPoints, cass_cluster_set_contact_points_n);
INT_SETTING(ATOMS.atomClusterSettingPort, cass_cluster_set_port);
CUSTOM_SETTING(ATOMS.atomClusterSettingSsl, internal_cass_cluster_set_ssl);
INT_SETTING(ATOMS.atomClusterSettingProtocolVersion, cass_cluster_set_protocol_version);
UNSIGNED_INT_SETTING(ATOMS.atomClusterSettingNumThreadsIo, cass_cluster_set_num_threads_io);
UNSIGNED_INT_SETTING(ATOMS.atomClusterSettingQueueSizeIo, cass_cluster_set_queue_size_io);
UNSIGNED_INT_SETTING(ATOMS.atomClusterSettingCoreConnectionsPerHost, cass_cluster_set_core_connections_per_host);
UNSIGNED_INT_SETTING(ATOMS.atomClusterSettingConnectTimeout, internal_cass_cluster_set_connect_timeout);
UINT64_SETTING(ATOMS.atomClusterSettingConstantReconnect, internal_cass_cluster_set_constant_reconnect);
CUSTOM_SETTING(ATOMS.atomClusterSettingExponentialReconnect, internal_cass_cluster_set_exponential_reconnect);
UINT64_SETTING(ATOMS.atomClusterSettingCoalesceDelay, cass_cluster_set_coalesce_delay);
INT_SETTING(ATOMS.atomClusterSettingRequestRatio, cass_cluster_set_new_request_ratio);
UNSIGNED_INT_SETTING(ATOMS.atomClusterSettingMaxSchemaWaitTime, internal_cass_cluster_set_max_schema_wait_time);
CUSTOM_SETTING(ATOMS.atomClusterSettingTokenAwareRoutingShuffleReplicas, internal_cass_cluster_set_token_aware_routing_shuffle_replicas);
CUSTOM_SETTING(ATOMS.atomClusterSettingSpeculativeExecutionPolicy, internal_set_speculative_execution_policy);
UNSIGNED_INT_SETTING(ATOMS.atomClusterSettingMaxReusableWriteObjects, cass_cluster_set_max_reusable_write_objects);
UNSIGNED_INT_SETTING(ATOMS.atomClusterSettingRequestTimeout, internal_cass_cluster_set_request_timeout);
UNSIGNED_INT_SETTING(ATOMS.atomClusterSettingHeartbeatInterval, internal_cass_cluster_set_connection_heartbeat_interval);
UNSIGNED_INT_SETTING(ATOMS.atomClusterSettingIdleTimeout, internal_cass_cluster_set_connection_idle_timeout);
CUSTOM_SETTING(ATOMS.atomClusterSettingCredentials, internal_cass_cluster_set_credentials);
CUSTOM_SETTING(ATOMS.atomClusterSettingLoadBalanceRoundRobin, internal_cass_cluster_set_load_balance_round_robin);
CUSTOM_SETTING(ATOMS.atomClusterSettingLoadBalanceDcAware, internal_cass_cluster_set_load_balance_dc_aware);
CUSTOM_SETTING(ATOMS.atomClusterSettingTokenAwareRouting, internal_cass_cluster_set_token_aware_routing);
CUSTOM_SETTING(ATOMS.atomClusterSetringLatencyAwareRouting, internal_cluster_set_latency_aware_routing);
CUSTOM_SETTING(ATOMS.atomClusterSettingTcpNodelay, internal_cass_cluster_set_tcp_nodelay);
CUSTOM_SETTING(ATOMS.atomClusterSettingTcpKeepalive, internal_cass_cluster_set_tcp_keepalive);
CUSTOM_SETTING(ATOMS.atomClusterSettingRetryPolicy, internal_cluster_set_retry_policy);
STRING_SETTING(ATOMS.atomClusterSettingCloudSecureConnectionBundle, cass_cluster_set_cloud_secure_connection_bundle_n);
return make_bad_options(env, term_option);
}
ERL_NIF_TERM nif_cass_cluster_create(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
cassandra_data* data = static_cast<cassandra_data*>(enif_priv_data(env));
if(data->cluster)
{
// this can happened in case the erlcass gen_server is crashes
cass_cluster_free(data->cluster);
data->cluster = NULL;
}
data->cluster = cass_cluster_new();
if(data->cluster == NULL)
return make_error(env, erlcass::kClusterObjectFailedToCreateMsg);
return ATOMS.atomOk;
}
ERL_NIF_TERM nif_cass_cluster_release(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
cassandra_data* data = static_cast<cassandra_data*>(enif_priv_data(env));
if(!data->cluster)
return make_error(env, erlcass::kClusterObjectNotCreatedMsg);
cass_cluster_free(data->cluster);
data->cluster = NULL;
return ATOMS.atomOk;
}
ERL_NIF_TERM nif_cass_cluster_set_options(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM options = argv[0];
if(!enif_is_list(env, options))
return make_bad_options(env, options);
cassandra_data* data = static_cast<cassandra_data*>(enif_priv_data(env));
ERL_NIF_TERM head;
const ERL_NIF_TERM* items;
int arity;
while(enif_get_list_cell(env, options, &head, &options))
{
if(!enif_get_tuple(env, head, &arity, &items) || arity != 2)
return make_bad_options(env, head);
ERL_NIF_TERM key = items[0];
ERL_NIF_TERM value = items[1];
if(!enif_is_atom(env, key))
return make_bad_options(env, head);
ERL_NIF_TERM result = apply_cluster_settings(env, head, key, value, data);
if(!enif_is_identical(ATOMS.atomOk, result))
return result;
}
return ATOMS.atomOk;
}
void cass_log_callback(const CassLogMessage* message, void* data)
{
if(data == NULL)
return;
ErlNifPid* pid = reinterpret_cast<ErlNifPid*>(data);
ErlNifEnv* env = enif_alloc_env();
ERL_NIF_TERM log_record = enif_make_tuple6(env,
ATOMS.atomLogMsgRecord,
enif_make_int(env, message->severity),
make_binary(env, message->file, strlen(message->file)),
enif_make_int(env, message->line),
make_binary(env, message->function, strlen(message->function)),
make_binary(env, message->message, strlen(message->message)));
enif_send(NULL, pid, env, enif_make_tuple2(env, ATOMS.atomLogMessageReceived, log_record));
enif_free_env(env);
}
ERL_NIF_TERM nif_cass_log_set_level(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int log_level;
if(!enif_get_int(env, argv[0], &log_level))
return make_badarg(env);
cass_log_set_level(static_cast<CassLogLevel>(log_level));
return ATOMS.atomOk;
}
ERL_NIF_TERM nif_cass_log_set_callback(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
cassandra_data* data = static_cast<cassandra_data*>(enif_priv_data(env));
if(enif_is_identical(argv[0], ATOMS.atomNull))
{
cass_log_set_callback(cass_log_callback, NULL);
}
else
{
if(!enif_get_local_pid(env, argv[0], &data->log_pid))
return make_badarg(env);
cass_log_set_callback(cass_log_callback, &data->log_pid);
}
return ATOMS.atomOk;
}