Driver shouldn't retry on client timeout if statement is not idempotent

Description

As stated in CASSANDRA-9086, the driver will automatically retry a CAS transaction whose connection has been disconnected while the transaction is in progress. This transaction will then silently retry on a new connection. This can break the client-observed linearizability of LWT, as shown below.

While the client can work around this for "IF NOT EXISTS" transactions, this behavior is not fixable for arbitrary state CAS.

For example, in the model of a CAS register with two concurrent clients, we can have the following flow:

REGISTER has state 1.
CLIENT 1 starts a LWT transaction that CAS 1 to 4.
CLIENT 1's connection drops but the transaction succeeds.
REGISTER has state 4.
CLIENT 2 concurrently has a LWT transaction to CAS 4 to 2.
CLIENT 2's transaction succeeds.
REGISTER has state 2.
CLIENT 1 retries the CAS from 1 to 4.
CLIENT 1 receives a failure to apply, since REGISTER has state 2.

From the perspective of clients, there has been one failed CAS from 1 to 4 and one successful CAS from 4 to 2. Given this history, there is no linearizable path from 1 to 2 for the register.

In general, the driver should never non-configurably retry LWT, instead throwing an exception that the user can handle.

Environment

None

Pull Requests

None

Status

Assignee

Unassigned

Reporter

Joel Knighton

Labels

None

PM Priority

A

Reproduced in

2.1.5

Affects versions

None

Fix versions

Pull Request

None

Doc Impact

None

Size

None

External issue ID

None

External issue ID

None

Sprint

Priority

Major
Configure