CompanyDecember 23, 2014

DataStax C/C++ Driver: RC1 released!

Michael Penick
Michael PenickDataStax
DataStax C/C++ Driver: RC1 released!

We are excited to announce the first release candidate of the DataStax C/C++ driver for Apache Cassandra and DataStax Enterprise. This release includes several bug fixes and improvements for both the driver's core and its API. We had to revisit a few API functions and introduce some breaking changes in order to ensure the future stability of the API and also fix some reported issues.

The most visible change is related to the creation and initialization of connections (CassCluster and CassSession). The API for logging, UUID and DCAware policy have also been improved. But these changes shouldn't require significant updates to your code and should be straightforward to implement. This post covers in detail each of these changes and how to migrate to the new API.

Starting with this RC we don't expect any API changes for the 1.0 GA release. Future major versions might introduce API changes but we will always try to minimize the number of such changes and document them thoroughly.

What’s new

Session API changes

In an effort to keep the CassCluster API as simple as possible, the driver previously combined the creation and connection of a CassSession object. As a consequence, the lifetime of the resulting CassSession object was linked to the connection future returned by cass_cluster_connect(). This lifecycle dependency introduced a possible thread leak in the case the connection future was cleaned up by the session thread. This issue could also be triggered by closing a session from a future callback. To resolve this issue the new API decouples the lifetime of the CassSession object from both the connect and close operations (and the corresponding futures).

The old API created and connected the CassSession object in a single step:

CassCluster* cluster = cass_cluster_new();

/* Configure cluster */

/* Create and connect session */
CassFuture* connect_future = cass_cluster_connect(cluster);
cass_future_wait(connect_future);

CassSession* session = cass_future_get_session(connect_future);
cass_future_free(connect_future);

/* Use session object */

/* Close the session */
CassFuture* close_future = cass_session_close(session);
cass_future_wait(close_future);
cass_future_free(close_future);

cass_cluster_free(cluster);

With the new API the session object is created separately and then it is connected:

CassCluster* cluster = cass_cluster_new();

/* Configure cluster */

/* Create and connect session */
CassFuture* connect_future = cass_cluster_connect(cluster);
cass_future_wait(connect_future);
CassSession* session = cass_future_get_session(connect_future);
cass_future_free(connect_future);

/* Use session object */

/* Close the session */
CassFuture* close_future = cass_session_close(session);
cass_future_wait(close_future);
cass_future_free(close_future);
cass_cluster_free(cluster);

With the new API the session object is created separately and then it is connected:

CassCluster* cluster = cass_cluster_new();

/* Configure cluster */

/* Explicitly create the session object */
CassSession* session = cass_session_new();

/* Connect the session */
CassFuture* connect_future = cass_session_connect(session, cluster);
cass_future_wait(connect_future);
cass_future_free(connect_future);

/* Use session object */

/* Close the session */
CassFuture* close_future = cass_session_close(session);

cass_future_wait(close_future);
cass_future_free(close_future);

cass_cluster_free(cluster);

/* Explicitly free the session object */
cass_session_free(session);


Global logging

In previous releases of the driver, logging was configured per session. Internally, this meant we needed to provide a logger instance to any code that needed to log. Injection of the logger object was not always possible which significantly limited where we could provide diagnostic information. This release makes logging global which allows driver code to log from anywhere. In addition to the internal improvements, the API also needed to be updated to accommodate this change.

Before, logging was configured per session object:

void custom_log_callback(cass_uint64_t time_ms,
                         CassLogLevel severity,
                         CassString message,
                         void
* data) {
  /* Log message */
}

void* log_data = NULL;

CassCluster* cluster = cass_cluster_new();
cass_cluster_set_log_level(cluster, CASS_LOG_DEBUG);
cass_cluster_set_log_callback(cluster, custom_log_callback, log_data);

CassFuture* connect_future = cass_cluster_connect(cluster);

/* Wait for future and retrieve session */



In the new API, logging is configured once before any other driver API call:


/* Notice: The method signature of a log callback has changed */

void custom_log_callback(const CassLogMessage* message,
                         void* data) {
  /* Log Message */
}

void* log_data = NULL;
cass_log_set_level(CASS_LOG_DEBUG);
cass_log_set_callback(custom_log_callback, log_data);

/* Configure cluster and connect session */

/* The logging system can be explicitly cleaned up. This is useful for applications that
* need to clean up log resources such as files.
 */
cass_log_cleanup();

/* Cleanup log resources (e.g. log file) */
 

The signature of a log callback has changed to include the file, line and function information on the log message.

Improved UUID API

The UUID API has been updated to use explicit initialization. In the previous betas, the driver's UUID library was statically initialized. There are general problems with static initialization and it doesn't allow for runtime configuration. The new library uses an explicitly created object called a UUID generator (CassUuidGen) instead of using global, internal state to generate UUIDs.

CassUuidGen* uuid_gen = cass_uuid_gen_new();

CassUuid uuid;
cass_uuid_gen_time(uuid_gen, &uuid);

/* Use generated UUID */

cass_uuid_gen_free(uuid_gen);
 

Data center aware (DC-aware) policy is now the default

Round-robin was the default load balancing policy in previous releases. In line with the other DataStax drivers, the RC1 uses the DC-aware policy as the default load balancing policy. Without configuration it uses the DC of the first connected contact point for the local DC, which makes it behave like the round-robin policy in single DC deployments. In multi-DC deployments, by default, the driver will not connect to any remote DC hosts. However, the DC-aware policy can be configured to use an explicitly provided local DC and also to use remote DC hosts during failure scenarios.

const char* local_dc = "dc1";

/* Use up to 2 remote hosts in each DC if there are not a sufficient number of local DC hosts */
unsigned used_hosts_per_remote_dc = 2;

/* Don't allow remote hosts if the consistency level is 
* CASS_CONSISTENCY_LOCAL_ONE or CASS_CONSISTENCY_LOCAL_QUORUM 
 */
cass_bool_t allow_remote_dcs_for_local_cl = cass_false;

cass_cluster_set_load_balance_dc_aware(cluster,
                                       local_dc,
                                       used_hosts_per_remote_dc, 
                                       allow_remote_dcs_for_local_cl);

Looking forward

This release brings the DataStax C/C++ driver one step closer to the general availability of version 1.0. It did introduced some breaking API changes, but those changes also help to improve and stabilize the driver's API. As of this release, there are no plans to make any changes to the API for 1.0 GA. We would like to hear your thoughts on the release and look forward to your feedback. 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.