Example #1
0
    def validate(self, stats=False):
        """
        Validate the ring.

        This is a safety function to try to catch any bugs in the building
        process. It ensures partitions have been assigned to real devices,
        aren't doubly assigned, etc. It can also optionally check the even
        distribution of partitions across devices.

        :param stats: if True, check distribution of partitions across devices
        :returns: if stats is True, a tuple of (device_usage, worst_stat), else
                  (None, None). device_usage[dev_id] will equal the number of
                  partitions assigned to that device. worst_stat will equal the
                  number of partitions the worst device is skewed from the
                  number it should have.
        :raises RingValidationError: problem was found with the ring.
        """

        if sum(d['parts'] for d in self._iter_devs()) != \
                self.parts * self.replicas:
            raise exceptions.RingValidationError(
                'All partitions are not double accounted for: %d != %d' %
                (sum(d['parts']
                     for d in self._iter_devs()), self.parts * self.replicas))
        if stats:
            # dev_usage[dev_id] will equal the number of partitions assigned to
            # that device.
            dev_usage = array('I', (0 for _junk in xrange(len(self.devs))))
            for part2dev in self._replica2part2dev:
                for dev_id in part2dev:
                    dev_usage[dev_id] += 1

        for part in xrange(self.parts):
            for replica in xrange(self.replicas):
                dev_id = self._replica2part2dev[replica][part]
                if dev_id >= len(self.devs) or not self.devs[dev_id]:
                    raise exceptions.RingValidationError(
                        "Partition %d, replica %d was not allocated "
                        "to a device." % (part, replica))

        if stats:
            weight_of_one_part = self.weight_of_one_part()
            worst = 0
            for dev in self._iter_devs():
                if not dev['weight']:
                    if dev_usage[dev['id']]:
                        # If a device has no weight, but has partitions, then
                        # its overage is considered "infinity" and therefore
                        # always the worst possible. We show 999.99 for
                        # convenience.
                        worst = 999.99
                        break
                    continue
                skew = abs(100.0 * dev_usage[dev['id']] /
                           (dev['weight'] * weight_of_one_part) - 100.0)
                if skew > worst:
                    worst = skew
            return dev_usage, worst
        return None, None
Example #2
0
    def validate(self, stats=False):
        """
        Validate the ring.

        This is a safety function to try to catch any bugs in the building
        process. It ensures partitions have been assigned to distinct zones,
        aren't doubly assigned, etc. It can also optionally check the even
        distribution of partitions across devices.

        :param stats: if True, check distribution of partitions across devices
        :returns: if stats is True, a tuple of (device usage, worst stat), else
                  (None, None)
        :raises RingValidationError: problem was found with the ring.
        """
        if sum(d['parts'] for d in self.devs if d is not None) != \
                self.parts * self.replicas:
            raise exceptions.RingValidationError(
                'All partitions are not double accounted for: %d != %d' %
                (sum(d['parts'] for d in self.devs if d is not None),
                 self.parts * self.replicas))
        if stats:
            dev_usage = array('I', (0 for _junk in xrange(len(self.devs))))
        for part in xrange(self.parts):
            zones = {}
            for replica in xrange(self.replicas):
                dev_id = self._replica2part2dev[replica][part]
                if stats:
                    dev_usage[dev_id] += 1
                zone = self.devs[dev_id]['zone']
                if zone in zones:
                    raise exceptions.RingValidationError(
                        'Partition %d not in %d distinct zones. ' \
                        'Zones were: %s' %
                        (part, self.replicas,
                         [self.devs[self._replica2part2dev[r][part]]['zone']
                          for r in xrange(self.replicas)]))
                zones[zone] = True
        if stats:
            weighted_parts = self.weighted_parts()
            worst = 0
            for dev in self.devs:
                if dev is None:
                    continue
                if not dev['weight']:
                    if dev_usage[dev['id']]:
                        worst = 999.99
                        break
                    continue
                skew = abs(100.0 * dev_usage[dev['id']] /
                           (dev['weight'] * weighted_parts) - 100.0)
                if skew > worst:
                    worst = skew
            return dev_usage, worst
        return None, None
Example #3
0
def validate_replicas_by_tier(replicas, replicas_by_tier):
    """
    Validate the sum of the replicas at each tier.
    The sum of the replicas at each tier should be less than or very close to
    the upper limit indicated by replicas

    :param replicas: float,the upper limit of replicas
    :param replicas_by_tier: defaultdict,the replicas by tier
    """
    tiers = ['cluster', 'regions', 'zones', 'servers', 'devices']
    for i, tier_name in enumerate(tiers):
        replicas_at_tier = sum(replicas_by_tier[t] for t in replicas_by_tier
                               if len(t) == i)
        if abs(replicas - replicas_at_tier) > 1e-10:
            raise exceptions.RingValidationError(
                '%s != %s at tier %s' %
                (replicas_at_tier, replicas, tier_name))
Example #4
0
    def validate(self, stats=False):
        """
        Validate the ring.

        This is a safety function to try to catch any bugs in the building
        process. It ensures partitions have been assigned to real devices,
        aren't doubly assigned, etc. It can also optionally check the even
        distribution of partitions across devices.

        :param stats: if True, check distribution of partitions across devices
        :returns: if stats is True, a tuple of (device_usage, worst_stat), else
                  (None, None). device_usage[dev_id] will equal the number of
                  partitions assigned to that device. worst_stat will equal the
                  number of partitions the worst device is skewed from the
                  number it should have.
        :raises RingValidationError: problem was found with the ring.
        """

        # "len" showed up in profiling, so it's just computed once.
        dev_len = len(self.devs)

        parts_on_devs = sum(d['parts'] for d in self._iter_devs())

        if not self._replica2part2dev:
            raise exceptions.RingValidationError(
                '_replica2part2dev empty; did you forget to rebalance?')

        parts_in_map = sum(len(p2d) for p2d in self._replica2part2dev)
        if parts_on_devs != parts_in_map:
            raise exceptions.RingValidationError(
                'All partitions are not double accounted for: %d != %d' %
                (parts_on_devs, parts_in_map))
        if stats:
            # dev_usage[dev_id] will equal the number of partitions assigned to
            # that device.
            dev_usage = array('I', (0 for _junk in xrange(dev_len)))
            for part2dev in self._replica2part2dev:
                for dev_id in part2dev:
                    dev_usage[dev_id] += 1

        for part, replica in self._each_part_replica():
            dev_id = self._replica2part2dev[replica][part]
            if dev_id >= dev_len or not self.devs[dev_id]:
                raise exceptions.RingValidationError(
                    "Partition %d, replica %d was not allocated "
                    "to a device." % (part, replica))

        for dev in self._iter_devs():
            if not isinstance(dev['port'], int):
                raise exceptions.RingValidationError(
                    "Device %d has port %r, which is not an integer." %
                    (dev['id'], dev['port']))

        if stats:
            weight_of_one_part = self.weight_of_one_part()
            worst = 0
            for dev in self._iter_devs():
                if not dev['weight']:
                    if dev_usage[dev['id']]:
                        # If a device has no weight, but has partitions, then
                        # its overage is considered "infinity" and therefore
                        # always the worst possible. We show MAX_BALANCE for
                        # convenience.
                        worst = MAX_BALANCE
                        break
                    continue
                skew = abs(100.0 * dev_usage[dev['id']] /
                           (dev['weight'] * weight_of_one_part) - 100.0)
                if skew > worst:
                    worst = skew
            return dev_usage, worst
        return None, None