def run(self): i = 1 # TODO pick i more intelligently? b = self.nextballot(0) # TODO same? v = None self._rpcclient.set_timeout(self._timeout) begin, retryphase1 = 1, 2 state = begin while True: if state == begin: v = self._queue.get() elif state == retryphase1: state = begin # Phase 1: resps = self._rpcclient.prepare(i, b) # We can only send our 'v' for acceptance if we have not already crossed # the Rubicon: if any other v *possibly* has quorum, we can't submit. # Each resp in resps is a ("promise", i, b, V, VB). maj, res_val = _majority(len(self._peers), [resp[3:5] for resp in resps]) if not maj: state = retryphase1 b = self.nextballot(b) continue # Instance is ready, proceed. Phase 2: if res_val is not None: v = res_val # Instance is reserved; we must choose this value. resps = self._rpcclient.accept(i, b, v) if not asyncrpc._is_majority(len(self._peers), resps): state = retryphase1 b = self.nextballot(b) continue # Instance is closed. Convey "learn" messages to local learner. self._learner.learn(i, v) i += 1
def _majority(n_peers, values): """ Takes in a number of peers, and a list of at most n_peers (V, VB) pairs. Returns (True, None) if the instance is empty. Returns (True, v) if the instance is reserved. Returns (False, None) if a quorum of acceptors failed to reply. """ if not asyncrpc._is_majority(n_peers, values): return (False, None) empty = True maxVB = None maxV = None for (V, VB) in values: if VB is not None and (empty or VB > maxVB): maxV = V maxVB = VB empty = False if empty: return (True, None) return (True, maxV)