From 1acd2aa8cfa40a8fe8cb01d7ae78157651058998 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Thu, 10 May 2018 19:07:12 -0600 Subject: [PATCH] Fix race condition in Accountant::apply_payment() --- src/accountant.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/accountant.rs b/src/accountant.rs index 39b190f5301f37..b884d5986c6ff5 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -33,12 +33,19 @@ pub type Result = result::Result; /// Commit funds to the 'to' party. fn apply_payment(balances: &RwLock>, payment: &Payment) { + // First we check balances with a read lock to maximize potential parallelization. if balances.read().unwrap().contains_key(&payment.to) { let bals = balances.read().unwrap(); bals[&payment.to].fetch_add(payment.tokens as isize, Ordering::Relaxed); } else { + // Now we know the key wasn't present a nanosecond ago, but it might be there + // by the time we aquire a write lock, so we'll have to check again. let mut bals = balances.write().unwrap(); - bals.insert(payment.to, AtomicIsize::new(payment.tokens as isize)); + if bals.contains_key(&payment.to) { + bals[&payment.to].fetch_add(payment.tokens as isize, Ordering::Relaxed); + } else { + bals.insert(payment.to, AtomicIsize::new(payment.tokens as isize)); + } } }