DataStax C/C++ Driver: 2.2 GA released!
We are pleased to announce the 2.2 GA release of the C/C++ driver for Apache Cassandra. This release includes all the features necessary to take full advantage of Apache Cassandra 2.2 including support for new data types ('tinyint', 'smallint', 'time', and 'date') and support for user defined function/aggregate (UDF/UDA) schema metadata. In addition to 2.2 features the release also brings with it the whitelist load balancing policy, a streamlined schema metadata API, and several internal improvements.
What's new
New data types
'tinyint' and 'smallint' can be used in cases where a smaller range would be a better fit than 'int' or 'bigint'.
CREATE TABLE integers (key text PRIMARY KEY,
tiny tinyint,
small smallint);
INSERTing the new 'tinyint' and 'smallint' types
CassStatement* statement = cass_statement_new(
"INSERT INTO integers (key, tiny, small)
"VALUES (?, ?, ?)");
cass_statement_bind_string(statement, "abc");
/* 'tinyint' is a signed 8-bit integer. It can represent values between -128 and 127 */
cass_statement_bind_int8(statement, 127);
/* 'smallint' is a signed 16-bit integer. It can represent values between -32768 and 32767 */
cass_statement_bind_int16(statement, 32767);
CassFuture* future = cass_session_execute(session, statement);
/* Handle future result */
/* CassStatement and CassFuture both need to be freed */
cass_statement_free(statement);
cass_future_free(future);
The 'date' type uses an unsigned 32-bit integer (cass_uint32_t
) to represent the number of days with Epoch (January 1, 1970) centered at 2^31. Because it's centered at Epoch it can be used to represent days before Epoch. The 'time' type uses a signed 64-bit integer (cass_int64_t
) to represent the number of nanoseconds since midnight and valid values are in the range 0 to 86399999999999. The following examples both use this schema:
CREATE TABLE date_time (key text PRIMARY KEY,
year_month_day date,
time_of_day time);
INSERTing the new 'date' and 'time' types
#include <time.h>
/* ... */
CassStatement* statement = cass_statement_new("INSERT INTO date_time (key, year_month_day, time_of_day) "
"VALUES (?, ?, ?)");
time_tnow =
time
(NULL);
/* Time in seconds from Epoch */
/* Converts the time since the Epoch in seconds to the 'date' type */
cass_uint_32_t year_month_day = cass_date_from_epoch(now);
/* Converts the time since the Epoch in seconds to the 'time' type */
cass_int64_t time_of_day = cass_time_from_epoch(now);
cass_statement_bind_string(statement, 0, "xyz");
/* 'date' uses an unsigned 32-bit integer */
cass_statement_bind_uint32(statement, 1, year_month_day);
/* 'time' uses a signed 64-bit integer */
cass_statement_bind_int64(statement, 2, time_of_day)
CassFuture* future = cass_session_execute(session, statement);
/* Handle future result */
/* CassStatement and CassFuture both need to be freed */
cass_statement_free(statement);
cass_future_free(future);
SELECTing the new 'date' and 'time' types
#include <time.h>
/* ... */
CassStatement* statement = cass_statement_new("SELECT * FROM examples.date_time WHERE key = ?");
CassFuture* future = cass_session_execute(session, statement);
constCassResult* result = cass_future_get_result(future);
/* Make sure there's a valid result */
if(result != NULL && cass_result_row_count(resut) > 0) {
constCassRow* row = cass_result_first_row(result);
/* Get the value of the "year_month_day" column */
cass_uint32_t year_month_day;
cass_value_get_uint32(cass_row_get_column(row, 1), &year_month_day);
/* Get the value of the "time_of_day" column */
cass_int64_t time_of_day
cass_value_get_int64(cass_row_get_column(row, 2), &time_of_day);
/* Convert 'date' and 'time' to Epoch time */
time_ttime
= (
time_t
)cass_date_time_to_epoch(year_month_day, time_of_day);
printf(
"Date and time: %s"
,
asctime
(
localtime
(&
time
)))
} else{
/* Handle error */
}
/* CassStatement and CassFuture both need to be freed */
cass_statement_free(statement);
cass_future_free(future);
Whitelist load balancing policy
By default the driver auto-discovers and connects to all the nodes in a Cassandra cluster. The whitelist load balancing policy can override this behavior by only connecting to a predefined set of hosts. This policy is useful for testing or debugging and is not optimal for production deployments. If the goal is to limit connections to a local data center then use the data center aware load balancing policy (cass_cluster_set_load_balance_dc_aware()
).
CassCluster* cluster = cass_cluster_new();
/* Enable a whitelist by setting a comma-delimited lists of hosts */
cass_cluster_set_whitelist_filtering(cluster, "127.0.0.1, 127.0.0.2, ...");
CassFuture* future = cass_session_connect(session, cluster);
/* ... */
cass_future_free(future);
cass_cluster_free(cluster);
New schema metadata API
This release improves the schema metadata API by adding concrete types for each of the different metadata types (CassKeyspaceMeta
, CassTableMeta
and CassColumnMeta
) instead of the single CassSchemaMeta
type used in the previous API. This allows for specific functions to handle each of the metadata types and better represents the metadata hierarchy i.e. user types, functions and aggregates metadata now live under the keyspace metadata. Applications that used the previous schema metadata API will require some small modifications to use the new API.
Retrieving a user defined type using the new API
/* Obtain a snapshot of the schema from the session */
constCassSchemaMeta* schema_meta = cass_session_get_schema_meta(session);
/* There is no need to free metadata types derived from the snapshot. Their lifetime's are bound
* the snapshot.
*/
constCassKeyspaceMeta* keyspace_meta = cass_schema_meta_keyspace_by_name(schema_meta,
"some_keyspace"
);
if(keyspace_meta != NULL) {
constCassDataType* some_user_type = cass_keyspace_meta_user_type_by_name(keyspace_meta,
"some_user_type"
);
/* Use user type */
} else
{
/* Handle error */
}
/* Only the snapshot needs to be freed */
cass_schema_meta_free(schema_meta);
A more complete example of using the new schema metadata API can be found here.
User function's and user aggregate's metadata
Cassandra 2.2 added user defined function (UDF) and aggregates (UDA). The 2.2 release of the C/C++ driver adds support to inspect the metadata of these new types.
Retrieving and printing UDF metadata
USE keyspace1;
CREATE FUNCTION multiplyBy (x int, n int)
RETURNS NULL ON NULL INPUT
RETURNS int LANGUAGE javascript AS 'x * n';
/* Obtain a snapshot of the schema metadata */
constCassSchemaMeta* schema_meta
= cass_session_get_schema_meta(session);
/* Search for the function's keyspace by name */
constCassKeyspaceMeta* keyspace_meta
= cass_schema_meta_keyspace_by_name(schema_meta, "keyspace1"
);
/* Search for the function by name and argument types (overloads are possible) */
constCassFunctionMeta* function_meta
= cass_keyspace_meta_function_by_name(keyspace_meta, "multiplyBy"
,
"int, int"
);
/* Inspect the function's metadata */
constchar
* full_name;
size_tfull_name_length;
cass_function_meta_full_name(function_meta, &full_name, &full_name_length);
constCassDataType* arg1_type = cass_function_meta_type_by_name(function_meta,
"x"
);
constCassDataType* arg2_type = cass_function_meta_type_by_name(function_meta,
"m"
);
constCassDataType* return_type = cass_function_meta_return_type(function_meta);
/* ... */
/* Only the snapshot needs to be freed */
cass_schema_meta_free(schema_meta);
Retrieving and printing UDA metadata
USE keyspace1;
CREATE OR REPLACE FUNCTION avgState ( state tuple<int,bigint>, val int ) CALLED ON
NULL INPUT RETURNS tuple<int,bigint> LANGUAGE java AS
'if (val !=null) { state.setInt(0, state.getInt(0)+1); state.setLong(1,
state.getLong(1)+val.intValue()); } return state;';
CREATE OR REPLACE FUNCTION avgFinal ( state tuple<int,bigint> ) CALLED ON NULL INPUT
RETURNS double LANGUAGE java AS
'double r = 0; if (state.getInt(0) == 0) return null; r = state.getLong(1); r/=
state.getInt(0); return Double.valueOf(r);';
CREATE AGGREGATE IF NOT EXISTS average ( int )
SFUNC avgState STYPE tuple<int,bigint> FINALFUNC avgFinal INITCOND (0,0);
/* Obtain a snapshot of the schema metadata */
constCassSchemaMeta* schema_meta
= cass_session_get_schema_meta(session);
/* Search for the aggregate's keyspace by name */
constCassKeyspaceMeta* keyspace_meta
= cass_schema_meta_keyspace_by_name(schema_meta, "keyspace1"
);
/* Search for the aggregate by name and argument types (overloads are possible) */
constCassAggregateMeta* aggregate_meta
= cass_keyspace_meta_aggregate_by_name(keyspace_meta, "multiplyBy"
,
"int, int"
);
/* Inspect the aggregate's metadata */
constchar
* full_name;
size_tfull_name_length;
cass_aggregate_meta_full_name(aggregate, &full_name, &full_name_length);
constCassFunctionMeta* avg_state_func = cass_aggregate_meta_state_func(aggregate_meta);
const
CassFunctionMeta* avg_final_func = cass_aggregate_meta_final_func(aggregate_meta);
constCassDataType* state_type = cass_aggregate_meta_state_type(aggregate_meta);
constCassDataType* return_type = cass_aggregate_meta_return_type(aggregate_meta);
constCassValue* init_cond = cass_aggregate_meta_init_cond(aggregate_meta);
/* ... */
/* Only the snapshot needs to be freed */
cass_schema_meta_free(schema_meta);
Internal improvements
This release also includes the following internal improvements:
- The default consistency is now
LOCAL_QUORUM
instead ofONE
- Improved the performance of string to/from conversion UUID functions
- Support for server-side warnings that are logged at the
CASS_LOG_WARN
level
Looking forward
This release brings with it full support for Apache Cassandra 2.2 along with many other great features. In the next release we will be focusing our efforts on supporting Apache Cassandra 3.0. Let us know what you think about the 2.2 GA release. Your feedback is important to us and it influences what features we prioritize. To provide feedback use the following:
- Mailing List: https://groups.google.com/a/lists.datastax.com/forum/#!forum/cpp-driver-user
- IRC: #datastax-drivers on irc.freenode.net
- Review and contribute source code: https://github.com/datastax/cpp-driver
- Report issues on JIRA: https://datastax-oss.atlassian.net/browse/CPP