CompanyApril 23, 2015

DataStax C/C++ Driver: 2.0 released!

DataStax C/C++ Driver: 2.0 released!

We are pleased to announce the 2.0 release of the DataStax C/C++ driver for Apache Cassandra and DataStax Enterprise. This release includes several new major features, mainly a latency aware routing policy and the addition of performance metrics, and improvements to the API including the removal of wrapper types (CassString, CassBytes, and CassDecimal), in favor of using plain C types, and the addition of string conversion functions for CassInet. The driver's internal dependency on Boost has also been removed.

What’s new

Latency-aware routing

The C/C++ driver now has the ability to track the latency of queries and avoid sending new queries to poorly performing Cassandra nodes. When enabled, this routing policy will track the exponentially weighted moving average of query latencies to nodes in the cluster. If a given node's latency exceeds an exclusion threshold, a factor of the minimum average latency of the entire cluster, it is no longer queried. The node is given a chance to recover and queries resume after a retry period. Both the exclusion threshold and the retry period are configurable settings for this policy. The latency-aware policy can be used with other load balancing policies including datacenter-aware, round-robin, and token-aware routing.

To enable latency-aware routing:

CassCluster* cluster = cass_cluster_new();

/* Latency-aware routing enabled with the default settings */
cass_cluster_set_latency_aware_routing(cluster, cass_true);

/* Connect sessions */

cass_cluster_free(cluster)


To change the default exclusion threshold and retry period:

CassCluster* cluster = cass_cluster_new();

/* Allow for up to 3.0 times (Default: 2.0) the best performing (minimum) latency */
cass_double_t exclusion_threshold = 3.0;

 /* Use the default scale */
cass_uint64_t scale_ms = 100;

/* Retry a node after 20 seconds (default: 10 seconds) even if it was performing poorly before */
cass_uint64_t retry_period_ms = 20000;

/* Find the best performing latency every 100 milliseconds */
cass_uint64_t update_rate_ms = 100;

/* Only consider the average latency of a node after it's been queried 50 times */
cass_uint64_t min_measured = 50;

cass_cluster_set_latency_aware_routing_settings(cluster,
                                                exclusion_threshold,
                                                scale_ms,
                                                retry_period_ms,
                                                update_rate_ms,
                                                min_measured);


/* Don't forget to enable latency-aware */
cass_cluster_set_latency_aware_routing(cluster, cass_true);

/* Connect sessions */

cass_cluster_free(cluster);

Metrics

Performance and diagnostic information have been added to the driver to help access application performance and debug issues. The performance metrics include information about request latencies and request throughput. The diagnostic metrics include information about the occurrence of various timeouts and up-to-date connection counts. A full list of the available metrics can be found in cassandra.h.

Check out the performance example to see the new metrics API in action.

CassInet string functions
This release includes the addition of CassInet string conversion functions.

Convert a CassInet to and from a string:

/* Connect session */

CassMetrics metrics;

/* Get a snapshot of the driver's metrics */
cass_session_get_metrics(session, &metrics);

printf("Current 99.9 percentile latency is: %llu\n"
, metrics.percentile_999th);

Check out the performance example to see the new metrics API in action.

CassInet string functions

This release includes the addition of CassInet string conversion functions.

Convert a CassInet to and from a string:

/* From string to CassInet */
CassInet inet;
cass_inet_from_string("127.0.0.1"
, &inet)

/* To string from CassInet */
char
ip_address[CASS_INET_STRING_LENGTH];
cass_inet_string(inet, ip_address);

Removal of CassString/CassBytes/CassDecimal

Previous version of the C/C++ driver used wrapper types to represent strings, bytes and decimal types. This provided a convenient way to encapsulate an array of data with its length. However, its use throughout the API was inconsistent, especially when it came to strings. Some functions would accept strings as null-terminated char arrays and others used CassString. These extra types also obfuscated the lifetime's of the memory pointed to by these objects. This release improves the API by removing these wrapper types and consistently uses two parameters in their place, a pointer to the data and the size of that data. For functions that take strings there are always two versions of that function, one that accepts a null-terminated char array, and one that makes the lengths explicit (these functions have the suffix "_n").

Functions that accepted CassStrings before look like this:

CassString query = cass_string_init("SELECT keyspace_name "
                                   "FROM system.schema_keyspaces"
);
CassStatement* statement = cass_statement_new(query, 0);

/* Use statement */

cass_statement_free(statement);

and now instead accept the string directly

CassStatement* statement = cass_statement_new("SELECT keyspace_name "
                                              "FROM system.schema_keyspaces"
, 0);

/* Use statement */

cass_statement_free(statement);

or can be used with an explicit lengths.

const char* query = "SELECT keyspace_name "
                    "FROM system.schema_keyspaces"
;
CassStatement* statement = cass_statement_new_n(query, strlen
(query), 0);

/* Use statement */
cass_statement_free(statement);


 All the examples have been updated with this change and are a good resource for migrating existing code.

Internal improvements

Boost was an internal dependency in previous versions of the C/C++ driver. This likely wasn't even known to most users of the driver because the required subset of the Boost source code was included in the driver itself. However, for some users this caused serious build issues because their applications also had a dependency on an older, but incompatible version of Boost. Instead of making Boost a required external dependency we've instead removed our dependency on Boost. There is still one external, but optional Boost dependency. Pre-2.0 the driver depended on Boost's implementation for lock-free and atomic operations. Moving forward the driver will allow for three choices for the implementation of atomic operations: std::atomic, a built-in intrinsics implementation and Boost Atomic. The built-in implementation works on all supported platforms, but can be slower than using the optimized versions found in std::atomic or Boost Atomic. On compilers that support the C++11 memory model the std::atomic implementation is automatically enabled, however; on older compilers and systems, to achieve maximum performance, it is recommended that the Boost Atomic implementation be used.

The std::atomic implementation can also be explicitly enabled:

cmake -DCASS_USE_STD_ATOMIC ...

When Boost is available (on older pre-C++11 compilers) its Atomics library can be used:

cmake -DCASS_USE_BOOST_ATOMIC ...

Note: Both of these implementations are entirely optional and the driver will work and perform well without them, but to achieve maximum performance they're recommended.

Looking forward

In addition to the new features and improvements we've also included a suite of new tests and have extensively tested this release. In the next release, we will be focusing on Cassandra 2.1 compatibility by including support for user-defined types, tuples and internally supporting native protocol version 3). Let us know what features you would like included in the next release. To provide feedback use the following:

Discover more
DriversC++
Share

One-stop Data API for Production GenAI

Astra DB gives JavaScript developers a complete data API and out-of-the-box integrations that make it easier to build production RAG apps with high relevancy and low latency.