hat.monitor.server.blessing

Implementation of blessing calculation algorithms

  1"""Implementation of blessing calculation algorithms"""
  2
  3from collections.abc import Iterable
  4import collections
  5import enum
  6import itertools
  7import time
  8
  9from hat.monitor import common
 10
 11
 12_next_tokens = itertools.count(1)
 13
 14
 15class Algorithm(enum.Enum):
 16    BLESS_ALL = 'BLESS_ALL'
 17    BLESS_ONE = 'BLESS_ONE'
 18
 19
 20def calculate(components: Iterable[common.ComponentInfo],
 21              group_algorithms: dict[str, Algorithm],
 22              default_algorithm: Algorithm
 23              ) -> Iterable[tuple[common.Mid, common.Cid, common.BlessingReq]]:
 24    """Calculate blessing request changes
 25
 26    Args:
 27        components: components state with previous blessing tokens
 28        group_algorithms: association of algorithm to group
 29        default_algorithm: default algorithm
 30
 31    Returns:
 32        blessing request changes
 33
 34    """
 35    group_components = collections.defaultdict(collections.deque)
 36    for c in components:
 37        group_components[c.group].append(c)
 38
 39    for group, components_from_group in group_components.items():
 40        algorithm = group_algorithms.get(group, default_algorithm)
 41
 42        yield from _calculate_group(algorithm, components_from_group)
 43
 44
 45def _calculate_group(algorithm, components):
 46    if algorithm == Algorithm.BLESS_ALL:
 47        yield from _bless_all(components)
 48
 49    elif algorithm == Algorithm.BLESS_ONE:
 50        yield from _bless_one(components)
 51
 52    else:
 53        raise ValueError('unsupported algorithm')
 54
 55
 56def _bless_all(components):
 57    for c in components:
 58        if not c.blessing_res.ready:
 59            blessing_req = common.BlessingReq(token=None,
 60                                              timestamp=None)
 61
 62        elif _has_blessing(c):
 63            blessing_req = c.blessing_req
 64
 65        else:
 66            blessing_req = common.BlessingReq(token=next(_next_tokens),
 67                                              timestamp=time.time())
 68
 69        if c.blessing_req != blessing_req:
 70            yield c.mid, c.cid, blessing_req
 71
 72
 73def _bless_one(components):
 74
 75    def highlander_battle(highlander, c):
 76        if not highlander:
 77            return c
 78        if c.rank < highlander.rank:
 79            return c
 80        if c.rank == highlander.rank:
 81            if _has_blessing(c) and not _has_blessing(highlander):
 82                return c
 83            if _has_blessing(c) and _has_blessing(highlander):
 84                if (c.blessing_req.timestamp <
 85                        highlander.blessing_req.timestamp):
 86                    return c
 87            if _has_blessing(c) and _has_blessing(highlander) or (
 88                    not _has_blessing(c) and
 89                    not _has_blessing(highlander)):
 90                if c.mid < highlander.mid:
 91                    return c
 92        return highlander
 93
 94    highlander = None
 95    for c in components:
 96        if not c.blessing_res.ready:
 97            continue
 98        highlander = highlander_battle(highlander, c)
 99
100    if highlander and not (highlander.blessing_res.token and
101                           highlander.blessing_res.token ==
102                           highlander.blessing_req.token):
103        for c in components:
104            if c.blessing_res.token and c != highlander:
105                highlander = None
106                break
107
108    for c in components:
109        if c != highlander:
110            blessing_req = common.BlessingReq(token=None,
111                                              timestamp=None)
112
113        elif not _has_blessing(c):
114            blessing_req = common.BlessingReq(token=next(_next_tokens),
115                                              timestamp=time.time())
116
117        else:
118            blessing_req = c.blessing_req
119
120        if c.blessing_req != blessing_req:
121            yield c.mid, c.cid, blessing_req
122
123
124def _has_blessing(component):
125    return (component.blessing_req.token and
126            component.blessing_req.timestamp)
class Algorithm(enum.Enum):
16class Algorithm(enum.Enum):
17    BLESS_ALL = 'BLESS_ALL'
18    BLESS_ONE = 'BLESS_ONE'
BLESS_ALL = <Algorithm.BLESS_ALL: 'BLESS_ALL'>
BLESS_ONE = <Algorithm.BLESS_ONE: 'BLESS_ONE'>
def calculate( components: Iterable[hat.monitor.common.ComponentInfo], group_algorithms: dict[str, Algorithm], default_algorithm: Algorithm) -> Iterable[tuple[int, int, hat.monitor.common.BlessingReq]]:
21def calculate(components: Iterable[common.ComponentInfo],
22              group_algorithms: dict[str, Algorithm],
23              default_algorithm: Algorithm
24              ) -> Iterable[tuple[common.Mid, common.Cid, common.BlessingReq]]:
25    """Calculate blessing request changes
26
27    Args:
28        components: components state with previous blessing tokens
29        group_algorithms: association of algorithm to group
30        default_algorithm: default algorithm
31
32    Returns:
33        blessing request changes
34
35    """
36    group_components = collections.defaultdict(collections.deque)
37    for c in components:
38        group_components[c.group].append(c)
39
40    for group, components_from_group in group_components.items():
41        algorithm = group_algorithms.get(group, default_algorithm)
42
43        yield from _calculate_group(algorithm, components_from_group)

Calculate blessing request changes

Arguments:
  • components: components state with previous blessing tokens
  • group_algorithms: association of algorithm to group
  • default_algorithm: default algorithm
Returns:

blessing request changes