I am currently facing a problem with an application that has deposit/withdraw functionality.
The underlying database (Cassandra) offers no read/write locks.
Now suppose user A has deposited 100$ in his account, He can use this credit to send 100 emails.
Imagine the following scenario:
User A opens two different tabs, t1 and t2, and points them the page for sending emails.
He fills in the fields on both tabs to send 100 emails and hits submit at almost the same time.
Now this happens in the background.
Time 0: t1 checks if the user has enough credit for sending 100 emails? True. He does.
Time 0.01: t2 checks if the user has enough credit for sending 100 emails? True. He does. (t1 has not updated the value of user's credit) .
Time 0.02: t1 updates the credit to 0 and goes on to sending 100 emails.
Time 0.03: t2 updates the credit to 0 and goes on to sending 100 emails.
The malicious user has now sent 200 emails while he had enough credits for sending only 100.
One approach would be to do a subtraction action instead of updating, in that case t2 would set the user's credit field to -100, but the user has already overspent his credit.
So, Here are my questions:
- What is the academic or more technical name of this problem? Race condition? Syncing problem?
- What are some approaches to prevent this from happening? This could happen anywhere where the database is distributed, like Amazon product inventories, or Visa Card.
How do they manage this situation that in peak times when two customers may purchase an item at the same time they don't oversell? or in the case of Visa, how do they prevent someone from withdrawing more than account's balance by copying his physical card and using it on two very distant ATMs? (thus increasing the probability that he'll hit two different database nodes that are not synced in real time because of the geographical distance.)
I'm very confused on this one,
Any help is so much appreciated.