The Java driver team is pleased to announce the release of version 2.0.11. The complete changelog can be found here, but we would like to highlight a few important items in this blog post. Also, make sure to read the upgrade guide.
Improvements to the Asynchronous API
There are now new methods to create a Session object asynchronously: Cluster.connectAsync()
and Cluster.connectAsync(String)
(JAVA-821). They return a ListenableFuture that will complete when the Session object is fully initialized, and all connection pools are up and running.
In addition, some internal features were refactored to avoid blocking calls (JAVA-822).
If you use the driver in a completely asynchronous manner, make sure to review this page in our documentation.
Improvements to Connection Handling
Each Cluster
instance maintains a “control connection” that is used to query schema and token metadata from the remote cluster, perform node discovery, and also to receive notifications such as schema or topology changes. This central piece of the driver’s architecture can sometimes be overwhelmed with lots of simultaneous queries and/or notifications; thanks to JAVA-657, all outbound queries and inbound notifications are now “debounced”, i.e. their execution is delayed and if two or more requests are received within the delay, they are “merged” together and only one query is executed or only one notification is processed. This can significantly reduce the network usage by the control connection, specially in large clusters or clusters with frequent schema changes. The debouncing delay is by default of 1 second, but it is configurable through several new options in QueryOptions; refer to the javadocs for more information.
Another noteworthy improvement is brought by JAVA-544: when a connection fails, the driver would mark the host down immediately and close all of its connections. But this behavior might be too agressive, specially if the host is the control host, because that would close the control connection as well; thanks to JAVA-544, the driver now keeps going with the remaining connections, and periodically tries to reopen the missing ones based on the configured ReconnectionPolicy
. It will only mark the host down when its last working connection goes down.
New RetryPolicy Decision: Try Next Host
DefaultRetryPolicy
‘s behavior has changed in the case of an UnavailableException
received from a coordinator. The new behavior will cause the driver to try a different host (the next one on the query plan) at most once, otherwise an exception will be thrown.
This change makes sense in the case where the node tried initially for the request happens to be isolated from the rest of the cluster (e.g. because of a network partition) but can still answer to the client normally. In this case, the isolated node will most likely respond with an UnavailableException
for most queries, but simply switching to another node – hopefully not isolated – those queries would most likely succeed. The previous behavior was to always rethrow the exception.
Improvements to Schema and Token Metadata API
Version 2.0.11 brings two important changes to the Schema and Token Metadata API:
First of all, thanks to JAVA-828, having the driver retrieve metadata is now optional; it’s of course enabled by default, but some applications might wish to disable it in order to eliminate the overhead of querying the metadata and building its client-side representation. This can now be done by setting QueryOptions.setMetadataEnabled(boolean)
to false. However, take note that doing so will have important consequences; refer to the javadocs for more information.
Furthermore, thanks to JAVA-151, clients can now subscribe to schema change notifications by implementing the new SchemaChangeListener
interface. The listener must then be registered against a Cluster
object through the new Cluster.register(SchemaChangeListener)
method.
Improvements to Prepared Statements
JAVA-797 introduces a new configuration parameter: QueryOptions.setPrepareOnAllHosts(boolean)
. This parameter controls whether the driver should prepare statements on all hosts in the cluster. A statement is normally prepared in two steps: first, prepare the query on a single host in the cluster; then, if that succeeds, prepare it on all other hosts. The new option controls whether the second step is executed. It is enabled by default. The reason why you might want to disable it is to optimize network usage if you have a large number of clients preparing the same set of statements at startup; the drawback is that if a host receives a BoundStatement
for a prepared statement that it does not know about, it will reply with an error and the driver will have to re-prepare the statement and re-execute the BoundStatement
, which obviously implies a performance penalty.
Should you keep the default settings and prepare your statements on all hosts, the whole operation will now be faster thanks to JAVA-725: all hosts are now prepared in parallel.
Another similar optimization has been introduced by JAVA-658: when a down node comes back up, the driver usually re-prepares all cached prepared statements on it. It is now possible to disable this default behavior by setting QueryOptions.setReprepareOnUp(boolean)
to false. The reason why you might want to disable it is to optimize reconnection time, but doing so can also incur in a performance penalty. See the javadocs for more details.
Netty Layer Configuration
Thanks to JAVA-853, it is now possible to configure the Timer
instance used by the Netty layer. Timer instances are used to trigger client timeouts and speculative executions.
By default the driver creates a new Timer
for every Cluster
, but this can lead to situations where the number of Timer
instances per JVM is too high; in these scenarios, users can now override the method NettyOptions.timer(ThreadFactory)
and provide their own implementation of Timer
(possibly shared among different Cluster
instances).
Improvements to Query Builder API
Version 2.0.11 ships with some nice additions to the Query Builder API:
- Support for
UPDATE ... IF EXISTS
: a CAS statement such asUPDATE table1 SET c1 = 'foo' WHERE pk = 1 IF EXISTS
can now be built with the Query Builder:update("table1").with(set("c1", "foo")).where(eq("pk", 1)).ifExists();
- Support for
SELECT DISTINCT
: a statement such asSELECT DISTINCT c1 FROM table1 WHERE pk = 1
can now be built with the Query Builder:select("c1").distinct().from("table1").where(eq("pk", 1));
- It is now possible to include bind markers when deleting list elements and map entries, e.g.
DELETE c1[?] FROM table1 WHERE pk = 1
andDELETE c1[:key] FROM table1 WHERE pk = 1
can now be expressed as follows:delete().listElt("c1", bindMarker()).from("table1").where(eq("pk", 1)); delete().mapElt("c1", bindMarker("key")).from("table1").where(eq("pk", 1));
- It is now possible to create
INSERT INTO
statements supplying columns and values as Lists, e.g.:INSERT INTO table1 (pk, c1) VALUES (1, "foo")
can now be built this way:List<String> columnNames = Lists.newArrayList("pk", "c1"); List<Object> columnValues = Lists.<Object>newArrayList(1, "foo"); insertInto("foo").values(columnNames, columnValues);
Logging & Debugging
Version 2.0.11 introduces two helpful tools to debug driver failures:
JAVA-720 now allows most exceptions thrown by the driver to report the coordinator address that triggered the error. A new interface CoordinatorException
has been introduced and most exceptions now implement it.
Thanks to JAVA-718 the driver now logs the stream ID of every request and response, at TRACE
level. This can be helpful to correlate requests and responses in your application logs.
JAVA-765 introduces a new method to retrieve values of a SimpleStatement: getObject(int)
which returns the value at the given index. This can also be useful to log statement values.
Authentication
Thanks to JAVA-719, PlainTextAuthProvider now accepts runtime modifications of the credentials, through two new methods: setUsername(String) and setPassword(String): the new credentials will be used for all connections initiated after these methods are called.
Getting the driver
As always, the driver is available from Maven and from our downloads server.
We’re also running a platform and runtime survey to improve our testing infrastructure. Your feedback would be most appreciated.