Added resilience computation.
This commit is contained in:
parent
59b2e746a4
commit
cf5e451d68
1 changed files with 53 additions and 9 deletions
|
@ -13,6 +13,8 @@ T = TypeVar('T')
|
||||||
|
|
||||||
|
|
||||||
class Expr(Generic[T]):
|
class Expr(Generic[T]):
|
||||||
|
# TODO(mwhittaker): This should probably be hidden. But, we might want a
|
||||||
|
# public version that is {node.x for node in nodes()}.
|
||||||
def nodes(self) -> Set['Node[T]']:
|
def nodes(self) -> Set['Node[T]']:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@ -261,20 +263,48 @@ class QuorumSystem(Generic[T]):
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'QuorumSystem(reads={self.reads}, writes={self.writes})'
|
return f'QuorumSystem(reads={self.reads}, writes={self.writes})'
|
||||||
|
|
||||||
|
def read_quorums(self) -> Iterator[Set[T]]:
|
||||||
|
return self.reads.quorums()
|
||||||
|
|
||||||
|
def write_quorums(self) -> Iterator[Set[T]]:
|
||||||
|
return self.writes.quorums()
|
||||||
|
|
||||||
|
def is_read_quorum(self, xs: Set[T]) -> bool:
|
||||||
|
return self.reads.is_quorum(xs)
|
||||||
|
|
||||||
|
def is_write_quorum(self, xs: Set[T]) -> bool:
|
||||||
|
return self.writes.is_quorum(xs)
|
||||||
|
|
||||||
|
def resilience(self) -> int:
|
||||||
|
return min(self.read_resilience(), self.write_resilience())
|
||||||
|
|
||||||
|
def read_resilience(self) -> int:
|
||||||
|
return self._min_hitting_set(self.read_quorums()) - 1
|
||||||
|
|
||||||
|
def write_resilience(self) -> int:
|
||||||
|
return self._min_hitting_set(self.write_quorums()) - 1
|
||||||
|
|
||||||
def strategy(self, read_fraction: Distribution) -> 'Strategy[T]':
|
def strategy(self, read_fraction: Distribution) -> 'Strategy[T]':
|
||||||
# TODO(mwhittaker): Allow read_fraction or write_fraction.
|
# TODO(mwhittaker): Allow read_fraction or write_fraction.
|
||||||
# TODO(mwhittaker): Implement independent strategy.
|
# TODO(mwhittaker): Implement independent strategy.
|
||||||
return self._load_optimal_strategy(
|
return self._load_optimal_strategy(
|
||||||
_canonicalize_distribution(read_fraction))
|
_canonicalize_distribution(read_fraction))
|
||||||
|
|
||||||
def is_read_quorum(self, xs: Set[T]) -> bool:
|
def _min_hitting_set(self, sets: Iterator[Set[T]]) -> int:
|
||||||
return self.reads.is_quorum(xs)
|
x_vars: Dict[T, pulp.LpVariable] = dict()
|
||||||
|
next_id = itertools.count()
|
||||||
|
|
||||||
def read_quorums(self) -> Iterator[Set[T]]:
|
problem = pulp.LpProblem("min_hitting_set", pulp.LpMinimize)
|
||||||
return self.reads.quorums()
|
for (i, xs) in enumerate(sets):
|
||||||
|
for x in xs:
|
||||||
|
if x not in x_vars:
|
||||||
|
id = next(next_id)
|
||||||
|
x_vars[x] = pulp.LpVariable(f'x{id}', cat=pulp.LpBinary)
|
||||||
|
problem += sum(x_vars[x] for x in xs) >= 1
|
||||||
|
|
||||||
def write_quorums(self) -> Iterator[Set[T]]:
|
problem += sum(x_vars.values())
|
||||||
return self.writes.quorums()
|
problem.solve(pulp.apis.PULP_CBC_CMD(msg=False))
|
||||||
|
return int(sum(v.varValue for v in x_vars.values()))
|
||||||
|
|
||||||
def _load_optimal_strategy(self,
|
def _load_optimal_strategy(self,
|
||||||
read_fraction: Dict[float, float]) -> \
|
read_fraction: Dict[float, float]) -> \
|
||||||
|
@ -340,6 +370,7 @@ class QuorumSystem(Generic[T]):
|
||||||
# return l.varValue
|
# return l.varValue
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Strategy(Generic[T]):
|
class Strategy(Generic[T]):
|
||||||
def load(self, read_fraction: Distribution) -> float:
|
def load(self, read_fraction: Distribution) -> float:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
@ -420,9 +451,11 @@ class ExplicitStrategy(Strategy[T]):
|
||||||
return np.random.choice(self.writes, p=self.write_weights)
|
return np.random.choice(self.writes, p=self.write_weights)
|
||||||
|
|
||||||
|
|
||||||
# a = Node('a', write_capacity=200, read_capacity=400)
|
|
||||||
# b = Node('b', write_capacity=100, read_capacity=200)
|
|
||||||
# c = Node('c', write_capacity=50, read_capacity=100)
|
# a = Node('a')
|
||||||
|
# b = Node('b')
|
||||||
|
# c = Node('c')
|
||||||
#
|
#
|
||||||
# qs = QuorumSystem(reads = a*b + a*c)
|
# qs = QuorumSystem(reads = a*b + a*c)
|
||||||
# print(list(qs.read_quorums()))
|
# print(list(qs.read_quorums()))
|
||||||
|
@ -438,10 +471,21 @@ class ExplicitStrategy(Strategy[T]):
|
||||||
# h = Node('h')
|
# h = Node('h')
|
||||||
# i = Node('i')
|
# i = Node('i')
|
||||||
# grid = QuorumSystem(reads=a*b*c + d*e*f + g*h*i)
|
# grid = QuorumSystem(reads=a*b*c + d*e*f + g*h*i)
|
||||||
|
# print(grid.resilience())
|
||||||
# sigma = grid.strategy(0.1)
|
# sigma = grid.strategy(0.1)
|
||||||
# print(grid)
|
# print(grid)
|
||||||
# print(sigma)
|
# print(sigma)
|
||||||
|
|
||||||
|
# paths = QuorumSystem(reads=a*b + a*c*e + d*e + d*c*b)
|
||||||
|
# print(paths.resilience())
|
||||||
|
# sigma = paths.strategy(read_fraction=0.5)
|
||||||
|
# print(sigma.load(read_fraction=0.5))
|
||||||
|
#
|
||||||
|
# walls = QuorumSystem(reads=a*b + c*d*e)
|
||||||
|
# print(walls.resilience())
|
||||||
|
# sigma = walls.strategy(read_fraction=0.5)
|
||||||
|
# print(sigma.load(read_fraction=0.5))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# wpaxos = QuorumSystem(reads=majority([majority([a, b, c]),
|
# wpaxos = QuorumSystem(reads=majority([majority([a, b, c]),
|
||||||
|
|
Loading…
Reference in a new issue