'Update the map of partition => [replicas] to be reassigned from
overweight drives where the replicas can be better dispersed to
another failure domain.
:param assign_parts: the map of partition => [replica] to update
:param start: offset into self.parts to begin search
:param replica_plan: replicanth targets for tiers'

def _gather_parts_for_balance_can_disperse(self, assign_parts, start, replica_plan):

    for offset in range(self.parts):
        part = ((start + offset) % self.parts)
        if (not self._can_part_move(part)):
            continue
        overweight_dev_replica = []
        replicas_at_tier = defaultdict(int)
        for replica in self._replicas_for_part(part):
            dev_id = self._replica2part2dev[replica][part]
            if (dev_id == NONE_DEV):
                continue
            dev = self.devs[dev_id]
            for tier in dev['tiers']:
                replicas_at_tier[tier] += 1
            if (dev['parts_wanted'] < 0):
                overweight_dev_replica.append((dev, replica))
        if (not overweight_dev_replica):
            continue
        overweight_dev_replica.sort(key=(lambda dr: dr[0]['parts_wanted']))
        for (dev, replica) in overweight_dev_replica:
            if any(((replica_plan[tier]['min'] <= replicas_at_tier[tier] < replica_plan[tier]['max']) for tier in dev['tiers'])):
                continue
            dev['parts_wanted'] += 1
            dev['parts'] -= 1
            assign_parts[part].append(replica)
            self.logger.debug('Gathered    %d/%d    from    dev    %s    [weight    disperse]', part, replica, pretty_dev(dev))
            self._replica2part2dev[replica][part] = NONE_DEV
            for tier in dev['tiers']:
                replicas_at_tier[tier] -= 1
            self._set_part_moved(part)
            break
