There are no table/row locks in Cassandra.

I believe swites from 2 different clients at (essentially precisely) the same time on the same table & row have no knowledge of one another. Each unique LWT did what was asked of it, read the data and wrote as requested. Last write won. This is the definition of eventual consistency, and you found an edge case for LWT usage.

There may be other suggestions, but I think the simplest method to get as close to a guarantee that your LWT functions as you wish, would be to take the parallel access out of the equation. Create a canonical user_app that is the only client writing to the user table. app1 and app2 make API calls to user_app and wait for its response, with some sort of application-level FIFO lock when multiple requests for the same row are in flight. The last write to the row still wins, but you control the timing to prevent the simultaneous-parallel edge case with LWT.

Michael

On 6/6/20 12:07 AM, Thiranjith Weerasinghe wrote:
Hi Everyone!


We have a 3-node Cassandra cluster (single DC), and a table that get accessed (for read/writes) by applications running on separate nodes.

Under heavy load, when both instances of the application are attempting to update the same user entry (E.g. add attribute) we observe that update from|app1|(running on|node1|succeeded - i.e.|ResultSet#wasApplied|returns|true|). However, when|app2|(on|node2|reads the data, it is getting stale data before|app1|updated it).

I'd like to know why this is happening because LTW with serial consistency should prevent this type of inconsistencies. Any help is much appreciated! We are using the datastax Java driver.

Thanks!

Thira



*Example:*(based on application logs)

 1. Initially the user has attribute|A|with value|1|
 2. Both|app1|and|app2|are adding new
    attributes;|app1|adding|B:2|and|app2|adding|C:3|
 3. |app1|read the correct data into memory, added new attribute|B|and
    wrote to Cassandra successfully. The logs show the final attribute
    list having|A:1|and|B:2|tuples.
 4. |app2|reads the data, but only see|A:1|(the difference in time
    between the logs from|app1|and|app2|is only 2ms; therefore could
    have happened in any order).
 5. Once|app2|'s write is completed, the end state only
    has|A:1|and|C:2|, which is incorrect.


*More Information*

The (prepared statements that perform) reads and writes to the table have the following characteristics: - Write is a LWT (on IF EXISTS userid) - Both read and writes use LOCAL_SERIAL consistency level

The table looks like (simple table with userid as the partition key):

    CREATE TABLE my_table(userid ascii PRIMARY KEY,attributes map);

The logic within the app when updating the attributes map is:

|

    |User user = dao.getUser(userid); user.addNewAttribute("key",
    "value"); dao.update(user);|
|






---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscr...@cassandra.apache.org
For additional commands, e-mail: user-h...@cassandra.apache.org

Reply via email to