Convergence Refinement Murat Demirbas Anish Arora The Ohio State University A basic question in fault-tolerance Is fault-tolerance preserved under program refinement ? In other words, given a high-level program A that is fault-tolerant , is a low-level implementation C of A yielded by a standard compiler or program transformer also fault-tolerant ? A counterexample: A toy infinite loop int x=0; while( x==x ) { x=0; } Java compiler • This program outputs 0 always – it is live even if x is corrupted • 0 1 2 5 6 7 8 9 12 iconst_0 istore_1 goto 7 iconst_0 istore_1 iload_1 iload_1 if_icmpeq 5 return Corresponding byte code can lose liveness – if x is corrupted between lines 7&8 Another counterexample: Bid Server High-level server: Sorted-list implementation of server: – maintains best K bids – stores best K bids in increasing order – replaces minimum stored bid x with an incoming bid v iff x<v • gracefully tolerates Byzantine failure of single bid location , – maintains (K-1) of best K bids – incoming bid is considered only if it is larger than head of list • does not tolerate single Byzantine failure: – e.g., of head of list So, what went wrong? Standard compilers and transformers yield refinements Intuitively, refinement means that every properly initialized computation of C is is a computation of A Refinements are clearly insufficient, because they don’t take into account states reached in the presence of faults E.g.: s* s* F s0 F s1 A s2 s3 … s0 s1 s2 C s3 … Fault-tolerance refinement isn’t just refinement What happens when compilers / transformers are modified to refine even from non-initialized states? ( Everywhere refinement ) Unfortunately, fault-tolerance preserving refinements are not always [ everywhere ] refinements [Leal 00] : intuitively because in the presence of faults C may not use the identical “recovery” path that A would In this paper, we develop an alternative notion of refinement that suffices for stabilization fault-tolerance preserving implementations applies also to masking fault-tolerance preserving implementations Outline of talk • Definition • Compositionality role in wrapper-based design of stabilization • An illustration deriving Dijkstra’s stabilizing programs from simple token rings Definition: Model • A system is an automaton (,T,I) : state space, T : set of transitions, I : set of initial states Computation is a maximal sequence of states-transitions pairs • C is stabilizing to A iff every computation of C has a suffix that is a suffix of some computation of A that starts at an initial state of A • Note: C and A may have different state spaces, relative to an abstraction function that is total and onto from C to A Definition: Convergence refinement [C A] C is a convergence refinement of A iff • C refines A , and • every computation c of C is a “compressed” form of some computation a of A Compressed means that c can omit a finite number of states in a, except its initial state and final state (if any) a = s1 s2 s3 s4 s5 s6 c = s1 s4 s6 a = s1 s2 s3 s4 s5 s6 c = s1 s0 s4 s6 Convergence refinement preserves stabilization C is a convergence refinement of A C tracks A from all states with only a finite number of compressions stabilization of A is preserved in C Theorem [C A] and A is stabilizing to B C is stabilizing to B Outline of talk • Definition • Compositionality role in wrapper-based design of stabilization • An illustration deriving Dijkstra’s stabilizing programs from simple token rings Compositionality of convergence refinement A desirable property of convergence refinement is that if the union of two high-level components is stabilizing, then so is the union of their low-level convergence refinements Lemma If [ C A ] , A W is stabilizing to A then [CW AW] and hence C W is also stabilizing to A Theorem If [CA], [ W’ W ] , then [ C W’ A W ] A W is stabilizing to A and hence C W’ is also stabilizing to A Outline of talk • Definition • Compositionality role in wrapper-based design of stabilization • An illustration deriving Dijkstra’s stabilizing programs from simple token rings Deriving Dijkstra’s token ring programs After all these years of staring at Dijkstra’s program , why chose them as the illustration ? No previous work has been able to derive Dijkstra’s programs as refinements of simple token rings Next Steps: 0 Chose a simple token ring program BTR 1. Add an abstract stabilization wrapper W to BTR 2. Convergence refine BTR into BTR4 and W into W’ • BTRW’ results in Dijkstra’s 4-state token ring program • The paper contains derivations for K-state & 3-state programs also Step 0: Bidirectional token ring, BTR • Propagate up-token at j: t.j t.j ; t.(j+1) • Bounce up-token at N: t.N t.N ; t.(N-1) • Propagate down-token at j t.j t.j ; t.(j-1) • Bounce down-token at 0 t.0 t.0 ; t.1 Step 1: Stabilization wrappers for BTR • W1 ensures that there exists at least one token in the system (j : jN: t.j t.j ) t.N • W2 ensures eventually at most one token exists in the system t.j t.j t.j ; t.j • (BTR W1 W2) is stabilizing to BTR • Notice that W1 accesses to global state Step 2: A 4 state implementation • How to localize W1 ? Implement bits t.j and t.j in terms of 2 bits: up.0 := true and up.N=false ensures that in any state there exists two adjacent processes that point to each other • Up-token at j : j and (j-1) point to each other c values at j and (j-1) differ formally , t.j c.j c.(j-1) up.(j-1) up.j • Down-token at j : j and (j+1) point to each other c values at j and j+1 are the same formally , t.j c.j=c.(j+1) up.(j+1) up.j up.j and c.j BTR after the mapping • Propagate up-token at j:j c.j up.(j-1) c.j = c.(j-1); up.j; t.j c.(j-1) t.j ;up.j t.(j+1) c.(j+1) c.j up.(j+1) • Bounce up-token at N: N c.N t.N c.(N-1) up.(N-1) t.N ; c.N = c.(N-1); t.(N-1) up.(N-1) • Propagate down-token at j c.j=c.(j+1) up.(j+1) up.j; t.j t.j; up.jt.(j-1) c.(j-1) = c.j up.(j-1) • Bounce down-token at 0 c.0=c.1 up.1 t.0 ; t.0 c.0 = c.0; t.1 up.1 Wrappers after the mapping • Applying the mapping to W1, we get (j : jN: up.j ) c.(N-1)c.N c.N= c.(N-1) up.(N-1) The guard already implies the statement, hence W1 is already implemented after the mapping • Since (t.j t.j false), W2 is also vacuously implemented after the mapping • So, the mapped BTR is trivially stabilizing BTR4: compressing the high atomicity actions Unfortunately, some of the actions in BTR are high atomicity, where j writes the state of j-1 or j+1 , e.g. • Propagate down-token at j c.j=c.(j+1) up.(j+1) up.j up.j; c.(j-1) = c.j up.(j-1) To reduce the atomicity, we convergence refine these actions by omitting write accesses to both neighbors • Propagate down-token at j c.j=c.(j+1) up.(j+1) up.j up.j // c.(j-1) = c.j up.(j-1) BTR4 is a convergence refinement of BTR c.0=1 up.1 c.1=1 up.2 c.2=1 c.3=1 t.0 t.0 c.0=1 up.1 c.1=1 up.2 c.2=1 c.3=1 Token at process 2 disappears after a propagate down-token action at process 2 t.2 t.1 t.0 Token at process 2 disappears only after two steps BTR4 • Propagate up-token at j c.j c.(j-1) // up.(j-1) up.j c.j = c.(j-1); up.j // c.(j+1) c.j up.(j+1) • Bounce up-token at N c.N c.(N-1) // up.(N-1) c.N = c.(N-1) // up.(N-1) • Propagate down-token at j c.j=c.(j+1) up.(j+1) up.j up.j // c.(j-1) = c.j up.(j-1) • Bounce down-token at 0 c.0=c.1 up.1 c.0 = c.0 // up.1 BTR4 W1’ W2’ = Dijkstra’s 4-state system • Up-token actions c.j c.(j-1) c.j = c.(j-1); up.j; c.N c.(N-1) c.N = c.(N-1); • Down-token actions c.j=c.(j+1) up.(j+1) up.j up.j; c.0=c.1 up.1 c.0 = c.0; Concluding remarks • One step in simplifying fault-tolerance implementation is to derive wrappers based not on the concrete code but on the abstract specification: Resettable vector clocks [PODC’00] Dependable home networking: Aladdin [IPDPS’02] We are developing tools and frameworks for mechanical, reusable synthesis of wrappers from abstract specifications • The second step is to use transformers that refine fault-tolerance : Everywhere-eventually refinements [ICDSN’01] AP to APC compiler [McGuire, Gouda] Since most such transformers still depend on the semantics of the input, we are developing fault-tolerance preserving compilers that depend only on syntax Continuous maintenance of network services • As one example, consider routing in sensor networks; it is required to dynamically adapt the fault-tolerance mechanisms to new environments • We have built a .NET framework for dynamic composition of fault-tolerance wrappers • We are using the Austin Protocol Compiler [Gouda, McGuire] that yields Ccode + UDP socket based communication while preserving certain stabilization properties to get concrete wrappers e.g., A–Routing dynamically W-ABP APC APC C–Routing W’–ABP