The condition “if exists” isn’t sufficient to guarantee only one app can write the row, the problem here is it’s mixing keys/values between app instances ?
What’s the actual schema here? > On Jun 6, 2020, at 7:16 AM, Michael Shuler <mich...@pbandjelly.org> wrote: > > 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 > --------------------------------------------------------------------- To unsubscribe, e-mail: user-unsubscr...@cassandra.apache.org For additional commands, e-mail: user-h...@cassandra.apache.org