'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.'

def validate(self, stats=False):

    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 = array('I', (0 for _junk in range(dev_len)))
        for part2dev in self._replica2part2dev:
            for dev_id in part2dev:
                dev_usage[dev_id] += 1
    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'])))
    int_replicas = int(math.ceil(self.replicas))
    rep2part_len = map(len, self._replica2part2dev)
    for part in range(self.parts):
        devs_for_part = []
        for (replica, part_len) in enumerate(rep2part_len):
            if (part_len <= part):
                if ((replica + 1) < int_replicas):
                    raise exceptions.RingValidationError(('The    partition    assignments    of    replica    %r    were    shorter    than    expected    (%s    <    %s)    -    this    should    only    happen    for    the    last    replica' % (replica, len(self._replica2part2dev[replica]), self.parts)))
                break
            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)))
            devs_for_part.append(dev_id)
        if (len(devs_for_part) != len(set(devs_for_part))):
            raise exceptions.RingValidationError(('The    partition    %s    has    been    assigned    to    duplicate    devices    %r' % (part, devs_for_part)))
    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']]:
                    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)
