Using abstract interpretation to correct synchronization faults Pietro Ferrara Omer Tripp Peng Liu Eric Koskinen JuliaSoft Google IBM Research Yale University VMCAI · 17 January 2017
Concurrency is here to stay.
… Thread 1 Thread 2 Thread n Queue HashMap List
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { Slot Res r = new Res() } 10:00 α val clobbered = map. replace (new_slot, r) return clobbered; 11:00 β } 12:00 γ 13:00 —
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { Slot Res r = new Res() } 10:00 α t 1 val clobbered = map. replace (new_slot, r) return clobbered; 11:00 β } t 2 12:00 γ 13:00 —
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { Slot Res r = new Res() } 10:00 α t 1 val clobbered = map. replace (new_slot, r) return clobbered; 11:00 β } t 2 12:00 γ t 1 goes first 13:00 — t 2 goes second t 1 : remove (10:00) / α t 2 : remove (13:00) / null t 1 : if (…) t 2 : new Res() / δ t 2 : replace (11:00) / β But returns δ ? Now: 11:00 —> α t 1 : replace (11:00) / δ t 1 : return δ Returns β ? Not serializable! t 2 : return β
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { Slot Res r = new Res() } 10:00 α t 1 val clobbered = map. replace (new_slot, r) return clobbered; 11:00 β } t 2 12:00 γ 13:00 — Acceptable Final States: t 1 first, returns β t 2 first, returns β t 2 second, returns α t 1 second, returns δ Slot Res Slot Res 10:00 — 10:00 — 11:00 δ 11:00 α 12:00 γ 12:00 γ 13:00 — 13:00 —
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { Slot Res r = new Res() } 10:00 α t 1 val clobbered = map. replace (new_slot, r) return clobbered; 11:00 β } t 2 12:00 γ 13:00 — Existing approaches to enforcing serializability . . .
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { Slot Res r = new Res() } t 1 10:00 α t 1 val clobbered = map. replace (new_slot, r) t 1 return clobbered; 11:00 β } t 2 12:00 γ t 2 Pessimistic 13:00 — t 1 : lock (10:00); lock (11:00) t 2 : lock (13:00); t 1 : remove (10:00) / α t 1 : if (…) t 1 : replace (11:00) / β t 1 : return β
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { Slot Res r = new Res() } t 1 10:00 α t 1 val clobbered = map. replace (new_slot, r) t 1 return clobbered; 11:00 β } t 2 12:00 γ t 2 Pessimistic 13:00 — t 1 : lock (10:00); lock (11:00) t 2 : lock (13:00); lock (11:00) t 1 : remove (10:00) / α t 1 : if (…) t 1 : replace (11:00) / β t 1 : return β
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { r = new Res() } val clobbered = map. replace (new_slot, r) return clobbered; } Pessimistic pessimis,c% remove if replace t 1 % get$ if(…)$ new$ putIfAbsent$ return$ remove new replace t 2 % get$ if(…)$ new$ putIfAbsent$ return$
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { r = new Res() } val clobbered = map. replace (new_slot, r) return clobbered; } Optimistic t 1 : remove (10:00) / α t 2 : remove (13:00) / null t 1 : if (…) t 2 : new Res() / δ t 2 : replace (11:00) / β t 1 : replace (11:00) / β t 1 : return β t 2 : return β
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { r = new Res() } val clobbered = map. replace (new_slot, r) return clobbered; } Optimistic t 1 : remove (10:00) / α t 2 : remove (13:00) / null t 1 : if (…) t 2 : new Res() / δ t 2 : replace (11:00) / β t 1 : replace (11:00) / β conflict. t 1 : return β t 2 : return β
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { r = new Res() } val clobbered = map. replace (new_slot, r) return clobbered; } Optimistic pessimis,c% remove if replace t 1 % get$ if(…)$ new$ putIfAbsent$ return$ remove new replace t 2 % get$ if(…)$ new$ putIfAbsent$ return$ remove if replace op,mis,c% t 1 % get$ if(…)$ new$ putIfAbsent$ return$ t 2 % remove new replace remove new replace get$ if(…)$ new$ putIfAbsent$ get$ if(…)$ new$ putIfAbsent$ return$ retry%
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { r = new Res() } val clobbered = map. replace (new_slot, r) return clobbered; } Other options? Perform a correction!
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { Slot Res r = new Res() } 10:00 α t 1 val clobbered = map. replace (new_slot, r) return clobbered; 11:00 β } t 2 12:00 γ 13:00 — t 1 : remove (10:00) / α t 2 : remove (13:00) / null t 1 : if (…) t 2 : new Res() / δ t 2 : replace (11:00) / β t 1 : replace (11:00) / δ t 1 : return δ Not serializable! t 2 : return β
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { Slot Res r = new Res() } 10:00 α t 1 val clobbered = map. replace (new_slot, r) return clobbered; 11:00 β } t 2 12:00 γ 13:00 —
Serializable Target t 1 first, returns β updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists t 2 second, returns α if (r == null) { Slot Res r = new Res() ♥ Slot Res } 10:00 — val clobbered = map. replace (new_slot, r) 10:00 — δ return clobbered; 11:00 β } 11:00 δ 12:00 γ 12:00 γ 13:00 — 13:00 — t 1 : remove (10:00) / α t 2 : remove (13:00) / null t 1 : if (…) t 2 : new Res() / δ t 2 : replace (11:00) / β α t 1 : replace (11:00) / δ β t 1 : return δ β t 2 : return β α
Serializable Target t 2 first, returns β updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists t 1 second, returns δ if (r == null) { Slot Res r = new Res() ♥ Slot Res } 10:00 — val clobbered = map. replace (new_slot, r) 10:00 — α return clobbered; 11:00 β } 11:00 α 12:00 γ 12:00 γ 13:00 — 13:00 — t 1 : remove (10:00) / α t 2 : remove (13:00) / null t 1 : if (…) t 2 : new Res() / δ t 2 : replace (11:00) / β t 1 : replace (11:00) / δ t 1 : return δ t 2 : return β
updateReservation(Slot old_slot, Slot new_slot) : Reservation = { var r = map. remove (old_slot) // remove if exists if (r == null) { r = new Res() } val clobbered = map. replace (new_slot, r) return clobbered; } Corrective pessimis,c% remove if replace t 1 % get$ if(…)$ new$ putIfAbsent$ return$ remove new replace t 2 % get$ if(…)$ new$ putIfAbsent$ return$ remove if replace op,mis,c% t 1 % get$ if(…)$ new$ putIfAbsent$ return$ t 2 % remove new replace remove new replace get$ if(…)$ new$ putIfAbsent$ get$ if(…)$ new$ putIfAbsent$ return$ retry% remove if replace correc,ve% t 1 % get$ if(…)$ new$ putIfAbsent$ return$ remove new replace t 2 % get$ if(…)$ new$ putIfAbsent$ return$ correct%
remove if replace correc,ve% t 1 % get$ if(…)$ new$ putIfAbsent$ return$ Corrective remove new replace t 2 % get$ if(…)$ new$ putIfAbsent$ return$ correct% Challenges & Contributions • Is this serializable? Yes, we have proved so. • How to compute each thread’s alternative post- states? Via a static abstract interpretation . • Given an incorrect state, how to efficiently recover to a correct post-state? Via a dynamic runtime system .
remove if replace correc,ve% t 1 % get$ if(…)$ new$ putIfAbsent$ return$ Corrective remove new replace t 2 % get$ if(…)$ new$ putIfAbsent$ return$ correct% Formalization Transition System
remove if replace correc,ve% t 1 % get$ if(…)$ new$ putIfAbsent$ return$ Corrective remove new replace t 2 % get$ if(…)$ new$ putIfAbsent$ return$ correct% Formalization Remember where we started t
remove if replace correc,ve% t 1 % get$ if(…)$ new$ putIfAbsent$ return$ Corrective remove new replace t 2 % get$ if(…)$ new$ putIfAbsent$ return$ correct% Formalization Remember the operation that was performed , op t ) L t ' , L t •op t )], σ , L ) Act sort of optimistically: march ahead w local changes
remove if replace correc,ve% t 1 % get$ if(…)$ new$ putIfAbsent$ return$ Corrective remove new replace t 2 % get$ if(…)$ new$ putIfAbsent$ return$ correct% Formalization Parameterize by property of interest (Serializability) , op t ) L t , L t •op t )], σ , L ) Replay the mutations on the shared state
Recommend
More recommend