Ensure atomicity of user_save within hook_node_delete In my system, a user has a number of bookings (nodes of content type 'booking') associated. Each of these bookings has a 'field_price' field and a 'field_customer_user' field (for which I am using the Entity Reference module) that links the booking to its customer. The user also has a 'field_bill' field containing the sum of all his bookings' prices.
Each time a booking gets deleted, I want to subtract its price from its user's bill. I'm doing it the following way, using hook_node_delete:
function mysite_node_delete($node) {
   if ($node-&gt;type == 'booking') {
     if ($account = user_load($node-&gt;field_customer_user[LANGUAGE_NONE][0]['target_id'])) {
       $bill = $account-&gt;field_bill[LANGUAGE_NONE][0]['value'];
       $bill -= $node-&gt;field_price[LANGUAGE_NONE][0]['value'];
       $account-&gt;field_bill[LANGUAGE_NONE][0]['value'] = $bill;
       user_save($account);
     }
   }
}

However, sometimes this does not work as expected. Given the following case:

User booking #1: 100$
User booking #2: 200$
User booking #3: 50$
Total bill: 350$

An administrator logs in and deletes all three bookings for this user sequentially, starting from booking #1 and finishing with booking #3. The user's total bill should be 0 now, but it ends up being

Total bill: 300$.

I guess that this means that when user_save($account) was called for booking #3, the user bill had not been properly updated by the first two calls to hook_node_delete. Therefore, the old value (350$) gets fetched and subtracted the price of booking #3, and end ups being 300$, which is not correct.
Is there anyway of making it work?
user_save() itself is likely to be guaranteed atomic. You're running innodb or equivalent, right?

However, you have no guarantees that the user isn't altered between your user_load() and user_save(), which can cause a race condition. There lock.inc for that. 


  A database-mediated implementation of a locking mechanism.


This is very unlikely though, and if this happens to you often and regularly, you likely have a problem elsewhere in your code.

However, not even that can protect you from other parts of the code, in a parallel request, loading up the user, modifying it, and saving it back, in between your calls. For better or worse, you can't reasonably guarantee that no other piece of code, such as contributed modules, modifies your users.

Suggested options:


Modify the field value directly like UPDATE [table] SET [field] = [field] +/- [value]. Then you can rely on the DB's underlying mechanisms for atomicity.
Accept a small risk of failure. Run a hourly cron job to recalculate values, correcting for mistakes.
Don't use a user field for this data. Either use a custom entity, or directly manage a custom table. Force all updates through a lock mechanism.