Jenny Liu created FINERACT-2902:
-----------------------------------

             Summary: Concurrent account transfers in opposite directions 
deadlock: 4 of 60 succeed, the others are answered with 409
                 Key: FINERACT-2902
                 URL: https://issues.apache.org/jira/browse/FINERACT-2902
             Project: Apache Fineract
          Issue Type: Bug
            Reporter: Jenny Liu


Measured on current develop (3f9f2a2), PostgreSQL, savings account to savings 
account transfers via POST /accounttransfers.

Test: 10 transfers A->B and 10 transfers B->A started at the same time, 3 
rounds. Result: 4 of 60 transfers succeeded, the other 56 were answered with 
HTTP 409. pg_stat_database reported 56 deadlocks for the run. The PostgreSQL 
log shows cycles of four sessions, all on
UPDATE "m_savings_account" SET ... WHERE (("id" = ?) AND ("version" = ?))
Money is conserved (the sum of both balances did not change), so this is an 
availability problem, not a correctness problem.

Cause: a transfer updates its source account first and then the destination 
account, without locking both in a defined order. Two transfers over the same 
pair of accounts in opposite directions each hold one row and wait for the 
other.

Proposal: lock both accounts at the start of the transfer in ascending id order 
(SELECT ... FOR UPDATE ORDER BY id), whatever the direction. With that change 
the same test gave 60 of 60 succeeded and 0 deadlocks; 20 transfers in one 
direction gave 20 of 20 with balances moved by exactly 20; a transfer above the 
balance is still rejected with 403.

Questions for maintainers: is an explicit pessimistic lock acceptable here, 
given that the rest of the savings code relies on optimistic locking? I have 
only tested PostgreSQL and the savings to savings case.
I have a branch with the change and unit tests and the test script.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to