Query timestamps

In Cassandra, each mutation has a microsecond-precision timestamp, which is used to order operations relative to each other.

There are various ways to assign it:

CQL USING TIMESTAMP

You can explicitly provide the timestamp in your CQL query:

session.execute("INSERT INTO my_table(c1, c2) values (1, 1) " +
    "USING TIMESTAMP 1432815430948040");

Client-side generation

This is enabled by default if you’re using the driver 3.0+ and a version of Cassandra that supports native protocol v3 or above.

A client timestamp will be sent by each query. It is generated by a TimestampGenerator. The default implementation is AtomicMonotonicTimestampGenerator.

You can specify another generator at initialization:

Cluster.builder().addContactPoint("127.0.0.1")
    .withTimestampGenerator(new MyCustomTimestampGenerator())
    .build();

In addition, you can also override the default timestamp on a per-statement basis:

Statement statement = new SimpleStatement(
    "UPDATE users SET email = 'x@y.com' where id = 1");
statement.setDefaultTimestamp(1234567890);
session.execute(statement);

Server-side generation

This is the “legacy” behavior if you’re connected to a Cassandra version that only supports protocol v2 or below. The server will assign a timestamp based on the time it receives the query.

This can be a problem when the order of the writes matter: with unlucky timing (different coordinators, network latency, etc.), two successive requests from the same client might be processed in a different order server-side, and end up with out-of-order timestamps. If protocol v3 is not an option, the only workaround is to add USING TIMESTAMP in your queries.

Summary

As shown in the previous sections, there are multiple ways to provide a timestamp, some of which overlap. The order of precedence is the following:

  1. if there is a USING TIMESTAMP clause in the CQL string, use that over anything else;
  2. otherwise, if a default timestamp was set on the statement and is different from Long.MIN_VALUE, use it;
  3. otherwise, if a generator is specified, invoke it and use its result if it is different from Long.MIN_VALUE;
  4. otherwise, let the server assign the timestamp.

Steps 2 and 3 only apply if native protocol v3 or above is in use.